Real-world examples

SVG scroll animations
without GSAP.

Ten production-ready patterns — logo reveals, charts, signatures, diagrams, Timeline API, Group API, Sequence API, and more. Each one is powered by svg-scroll-draw and works in React, Next.js, Vue, and vanilla JS. Scroll down to see them draw live.

01

·onComplete · fill transition

Logo Reveal

The Discord logo strokes itself in as an outline, then floods with color on completion — followed by a right-eye blink. Uses onComplete to trigger the fill transition and blink sequence.

Hero.tsx
// 1. stroke draws on scroll (fill starts transparent)
// 2. onComplete: fill floods in + right eye blinks

<ScrollDraw easing="ease-out" speed={0.95} once
  onComplete={handleComplete}>
  <svg viewBox="0 0 127.14 96.36">
    <path d="M107.7,8.07…"
      fill={filled ? '#5865F2' : 'transparent'}
      stroke="#5865F2" strokeWidth="2.5"
      style={{ transition: 'fill 0.45s ease' }} />

    {/* Left eye — floods white on complete */}
    <ellipse cx="42.45" cy="53.03" rx="11.42" ry="12.67"
      fill={filled ? 'white' : 'transparent'}
      style={{ transition: 'fill 0.45s ease' }} />

    {/* Right eye — blinks via scaleY */}
    <ellipse cx="84.69" cy="53.03" rx="11.42" ry="12.67"
      fill={filled ? 'white' : 'transparent'}
      style={{ transform: `scaleY(${blinking ? 0.05 : 1})`,
               transformBox: 'fill-box', transformOrigin: 'center',
               transition: 'fill 0.45s ease, transform 0.1s ease-in-out' }} />
  </svg>
</ScrollDraw>
Discord

02

·selector · strokeColor

Revenue Chart

Monthly revenue line draws itself across the chart axes on scroll — axes animate first, then the data line traces in with a color shift from grey to brand pink.

Hero.tsx
<ScrollDraw
  easing="ease-in-out" speed={0.85} once
  selector=".ink"
  strokeColor={['#e2e8f0', '#ff90e8']}
>
  <svg>
    {/* Static: grid, labels, data points, area */}
    {/* .ink elements animate: axes + data line */}
    <line className="ink" {/* y-axis */} />
    <line className="ink" {/* x-axis */} />
    <path className="ink" d="M 55 138 C…" {/* data line */} />
  </svg>
</ScrollDraw>
$80k$60k$40k$20kJanFebMarAprMayJunJul

03

·stagger · ease-out

Contract Signature

CEO signature draws on scroll with a staggered underline flourish — label, printed name and date are static context. Looks like ink drying on a real document.

Hero.tsx
<ScrollDraw
  easing="ease-out" speed={0.6}
  stagger={0.35} once
>
  <svg>
    {/* Static: "Authorized Signature" label, name, date */}
    {/* Animated path 1: cursive signature */}
    <path d="M 18 90 C 14 62…" stroke="#111" strokeWidth="2.2" />
    {/* Animated path 2: underline flourish (starts after sig) */}
    <path d="M 12 112 C 90 122…" stroke="#ff90e8" />
  </svg>
</ScrollDraw>
Authorized SignatureJ. Anderson, CEOMay 2026

04

·selector · stagger

Checkout Flow

Box borders and arrow connectors draw in sequence across a 4-step checkout process. Static fills and emoji keep the diagram readable before animation starts.

Hero.tsx
<ScrollDraw
  easing="ease-out" speed={1.1}
  selector=".ink" stagger={0.18} once
>
  <svg>
    {/* Static: filled boxes + emoji + step labels */}
    <rect x={8}   fill="#f0f4ff" />{/* Cart */}
    <rect x={82}  fill="#fff8f0" />{/* Shipping */}
    {/* .ink elements animate: borders + arrows */}
    <rect className="ink" x={8}  stroke="#5865F2" />
    <path className="ink" d="M 70 70 L 82 70" {/* arrow */} />
  </svg>
</ScrollDraw>
🛒Cart📦Shipping💳PaymentConfirmed01020304

05

·selector · strokeColor

Delivery Route

A delivery route traces itself across a city block map — warehouse to customer. City blocks, street names and the distance badge are static; only the route line animates.

Hero.tsx
<ScrollDraw
  easing="ease-in-out" speed={0.75} once
  selector=".ink"
  strokeColor={['#fbbf24', '#ff90e8']}
>
  <svg>
    {/* Static: city blocks, street labels, distance badge */}
    {/* Static: start/end markers */}
    {/* Animated: route path only */}
    <path className="ink"
      d="M 44 175 L 44 132 L 90 132…"
      stroke="#fbbf24" strokeWidth="4" />
  </svg>
</ScrollDraw>
Oak StMain Ave1st StWWarehouseCCustomer2.4 km · 8 min

06

·selector · ease-out

API Architecture

Connection lines between services draw in on scroll — Browser → API Gateway → Auth / Database / Cache. Service boxes and labels are always visible; only the wires animate.

Hero.tsx
<ScrollDraw
  easing="ease-out" speed={1.1} once
  selector=".ink"
>
  <svg>
    {/* Static: labeled service boxes */}
    <rect … /><text>🌐 Browser</text>
    <rect … /><text>API Gateway</text>
    {/* .ink lines draw the connections */}
    <line className="ink" {/* Browser → API */} />
    <line className="ink" {/* API → Auth */} strokeDasharray="4 3" />
    <line className="ink" {/* API → DB */}   strokeDasharray="4 3" />
    <line className="ink" {/* API → Cache */} strokeDasharray="4 3" />
  </svg>
</ScrollDraw>
🌐 BrowserAPI Gateway🔐 Auth🗄️ Database⚡ Cache

07

·data-scroll-draw · initScrollDraw()

Astro Integration

Zero-JS server components — add data-scroll-draw to any element and call initScrollDraw() in a client script. Options are passed as a JSON attribute. No framework wrapper needed.

Hero.tsx
// src/pages/index.astro
---
// No server-side imports needed
---

<div
  data-scroll-draw
  data-scroll-draw-options='{"easing":"ease-out","fade":true,"once":true}'
>
  <svg viewBox="0 0 200 80" fill="none">
    <path d="M10 40 Q100 5 190 40"
      stroke="white" strokeWidth="2" />
  </svg>
</div>

<script>
  import { initScrollDraw } from 'svg-scroll-draw/astro';

  // Finds all [data-scroll-draw] on the page and
  // initialises each one — no React, no Vue needed.
  initScrollDraw();
</script>
src/pages/index.astro
<div data-scroll-draw
data-scroll-draw-options='{"easing":"ease-out","once":true}'
>
<svg viewBox="0 0 200 80">
<path d="M10 40 Q100 5 190 40"
stroke="white" fill="none" />
</svg>
</div>
<script>
import { initScrollDraw } from 'svg-scroll-draw/astro';
initScrollDraw();
</script>

08

·scrollDrawTimeline · independent tracks

Timeline API

Four quarterly bars and a trend line — each animated on its own independent scroll window using scrollDrawTimeline. Axes draw first (0→28%), then Q1–Q4 bars stagger across (10→88%), and the trend line traces last (75→100%) once all bars are fully visible.

Hero.tsx
import { scrollDrawTimeline } from 'svg-scroll-draw/timeline';

// Each track owns its own from/to slice of the scroll range.
// Unlike stagger (time offset), windows can overlap freely.
scrollDrawTimeline('#chart', {
  trigger: { start: 'top 88%', end: 'top 25%' },
  tracks: [
    { selector: '.axis',  from: 0,    to: 0.28, easing: 'ease-out' },
    { selector: '.bar-1', from: 0.1,  to: 0.42, easing: 'ease-out' },
    { selector: '.bar-2', from: 0.26, to: 0.56, easing: 'ease-out' },
    { selector: '.bar-3', from: 0.42, to: 0.72, easing: 'ease-out' },
    { selector: '.bar-4', from: 0.58, to: 0.88, easing: 'ease-out' },
    // Trend line draws only after all bars are visible
    { selector: '.trend', from: 0.75, to: 1.0,  easing: 'spring'   },
  ],
});
$0k$40k$80k$120kQ1$92kQ2$122kQ3$77kQ4$111kEach bar is an independent track

09

·scrollDrawGroup · synchronized

Group API

Three separate SVG containers — Speed, Size, and Framework icons — all animate simultaneously the moment the section scrolls into view. scrollDrawGroup wires them to the same scroll timeline with one call.

Hero.tsx
import { scrollDrawGroup } from 'svg-scroll-draw/group';

// All three containers share the same options and
// start drawing at exactly the same scroll position.
const group = scrollDrawGroup(
  [speedRef.current, sizeRef.current, frameworkRef.current],
  {
    easing: 'ease-out',
    speed:  1.1,
    fade:   true,
    once:   true,
    trigger: { start: 'top 88%', end: 'top 25%' },
  }
);

// One call controls all instances
group.replay();
group.pause();
group.destroy(); // cleanup on unmount
Speed
~3 KB
Any framework

10

·scrollDrawSequence · one after another

Sequence API

Three steps — Code, Build, Ship — draw in strict sequence: each one starts only after the previous reaches 100%. The border and label color up as each step completes. Uses scrollDrawSequence with onComplete to track state.

Hero.tsx
import { scrollDrawSequence } from 'svg-scroll-draw/group';

// Each container starts drawing only after
// the previous one fully completes.
const seq = scrollDrawSequence(
  [codeRef.current, buildRef.current, shipRef.current],
  {
    easing:     'ease-out',
    speed:      1.4,
    fade:       true,
    trigger:    { start: 'top 88%', end: 'top 25%' },
    onComplete: () => setStep((s) => s + 1),
  }
);

seq.replay();   // restart from step 1
seq.destroy();  // cleanup on unmount

01

Code

02

Build

03

Ship

Ready to add this
to your project?