Lottie Scroll Line Draw — Scroll-Drawn SVG Path

Lottie Scroll Line Draw · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Lottie JSON built in code with keyframe helpers — no exported file, nothing to fetch or 404
Every animated keyframe carries i/o easing tangents so lottie-web interpolates instead of holding
The draw effect is a Lottie trim path (tm) animating its end from 0 to 100 across the timeline
A filled dot rides the leading edge, its position sampled from the same wave function each frame
Faint static copy of the path behind the drawn line acts as an always-visible route track
autoplay: false + goToAndStop(frame, true): scroll position, not a timer, decides the frame
Fully reversible — scrolling up seeks smaller frames and erases the line for free
SVG renderer with a CSS drop-shadow glow, crisp at any size and easy to recolour

About this UI Snippet

How to Draw a Lottie Line on Scroll With a Trim Path, lottie-web and GSAP

Screenshot of the Lottie Scroll Line Draw snippet rendered live

The Lottie Scroll Line Draw snippet strokes a flowing wave onto the screen as the visitor scrolls, with a glowing dot riding the leading edge of the line, and erases it again on the way back up. Nothing plays on a timer — the scrollbar drives the animation frame by frame — and the whole Lottie is generated in JavaScript rather than exported from After Effects, so you can see exactly how the drawing effect is built.

Lottie is JSON, and here it is built in code

A Lottie animation is a JSON document of vector layers and keyframes. Most tutorials fetch one with lottie.loadAnimation({ path: 'anim.json' }), but this snippet constructs the JSON object directly and passes it as animationData, so there is nothing to host and nothing that can 404. A pair of tiny helpers — one for scalar keyframes, one for multi-value keyframes — assemble the animation, and both always attach the easing tangents every animated keyframe needs.

The one keyframe detail that matters most

When you author a Lottie by hand, every animated keyframe must carry its i (in) and o (out) bezier tangents. Omit them and lottie-web treats the keyframe as a hold keyframe: it never interpolates, and the value stays frozen at the first keyframe forever. For a trim animating 0 to 100 that means the line never draws. The helpers here set linear tangents with control points at 0.5/0.5 on every keyframe, which is why the line grows smoothly instead of staying blank.

The draw effect is a trim path

The wave itself is a dense polyline — a sine sampled at sixty-odd points — wrapped in a Lottie trim path (shape type tm). A trim path renders only a portion of a stroked path, from a start percentage to an end percentage. Animating the trim's end from 0 to 100 across the timeline makes the stroke look like it is being drawn by a pen. A second, faint copy of the exact same path sits behind it with no trim, so the full route is always faintly visible — the same idea as a progress track. This is the vector equivalent of animating stroke-dashoffset on an SVG path, but expressed inside the Lottie so it travels with the animation.

A dot that rides the tip

To make the draw feel alive, a filled dot follows the leading edge of the line. Because the trim end and the dot both advance linearly over the same 120 frames, the tip position is predictable: the snippet samples the wave function at regular frames and keyframes the dot's position to match. The result is a dot that appears to be pulling the line into existence as you scroll.

Autoplay off, scroll on

The animation is loaded with autoplay: false so its internal clock never runs. Instead a GSAP ScrollTrigger pins the stage and scrubs a single plain value from 0 to 1 as the visitor scrolls through a range several viewport-heights tall. A requestAnimationFrame loop reads that value every frame and calls anim.goToAndStop(p * (totalFrames - 1), true) — the true tells lottie-web the value is a frame number, and goToAndStop renders a single still frame without starting playback. Because lottie-web interpolates between keyframes, fractional frames render smoothly.

Reversible for free

Deriving the frame from one scrubbed value means scrolling up simply produces smaller values, so the line un-draws and the dot travels backward with no extra reverse-playback code. A smoothed scrub: 0.5 lets the drawing glide toward the scroll position rather than snapping to every noisy wheel tick, and the intro caption fades out the moment drawing begins. Pair it with the ring-drawing Lottie scroll scrub or a scroll typewriter for a full scroll-driven sequence.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not have to work out how a JSON file becomes a scroll-drawn line by hand. Paste this snippet's HTML, CSS, and JS into an AI assistant like Claude and ask it to walk through why every keyframe needs i/o tangents, what goToAndStop's second argument does, or how the trim path draws the stroke. The same assistant can help you extend it — ask it to replace the wave with your own path, add a second line that draws after the first, make the dot leave a fading trail, or load an external Lottie file instead of the inline JSON. Treat the code as a conversation starter, not a finished artifact.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "scroll-drawn Lottie line" in plain HTML, CSS, and JavaScript using lottie-web and GSAP's ScrollTrigger plugin, both from a CDN (no bundler).

Requirements:
- A pinned full-height section with a centered container div for the Lottie, an intro caption overlay, and a live "percent drawn" read-out.
- Build the Lottie as an inline animationData JSON object (leave a comment showing how to swap it for path: 'your-animation.json'). Include small helpers that build scalar and multi-value keyframes and ALWAYS attach i/o easing tangents (linear, control points 0.5/0.5) — without them lottie-web holds the value and the animation stays blank.
- The animation is a flowing sine-wave polyline drawn on via an animated trim path (type 'tm') whose end goes 0 to 100, with a faint static copy of the path behind it as a track, plus a filled dot whose position is keyframed to ride the leading edge of the draw (sample the same wave function per frame).
- Load with lottie.loadAnimation using renderer 'svg', loop false, autoplay FALSE.
- Register a GSAP tween on a ScrollTrigger targeting the pinned section, with pin true, start at top top, scrub around 0.5, and an end several hundred percent tall, animating one value p from 0 to 1.
- In a requestAnimationFrame loop, read p and call anim.goToAndStop(p * (anim.totalFrames - 1), true), update the read-out, and fade the caption out once p passes a small threshold.
- Confirm scrolling up reverses the draw.

Step by step

How to Use

  1. 1
    Load the three CDN scriptsAdd lottie.min.js, gsap.min.js, and ScrollTrigger.min.js from the CDN panel, in that order.
  2. 2
    Paste the HTML, CSS, and JSA faint wave track appears centred in a pinned stage with a live "% drawn" read-out.
  3. 3
    Scroll downThe coloured line strokes on left to right and a dot rides its leading edge, tied directly to scroll position.
  4. 4
    Scroll back upThe line un-draws exactly, because goToAndStop seeks a single frame rather than playing on a timer.
  5. 5
    Reshape the lineEdit the wave function (amplitude, cycles) or replace the generated points with your own path to draw any shape.
  6. 6
    Tune the lengthChange the ScrollTrigger end value (+=400%) for a longer, slower draw or a shorter, quicker one.

Real-world uses

Common Use Cases

Signature and route reveals
Draw a signature, a delivery route, or a hand-drawn underline exactly as the reader scrolls into the section, so the line feels drawn in real time.
Section dividers with motion
Use a drawn line as a scroll-reactive divider between page sections, giving long-form pages a sense of progress and craft.
Simple trend lines
Swap the wave for a data path and let a line chart draw itself on scroll, a lightweight vector alternative to a full charting library.
Storytelling connectors
Connect steps in a narrative or timeline with a line that draws between them as the visitor moves down the page.
Learn Lottie trim paths
A compact, readable example of building a Lottie in code and animating a trim path — the core of every draw-on effect. Pair it with the Lottie scroll scrub ring.
Hero background accents
A drawn line makes a subtle, premium hero accent that reacts to scroll without the weight of a video.

Got questions?

Frequently Asked Questions

Constructing the animationData object directly keeps the snippet self-contained — there is no second network request, nothing to host, and nothing that can 404 or be blocked by a sandbox. It also makes the drawing logic visible and editable. For your own project you can load an external file instead: delete the animationData object and pass path: "your-animation.json" to loadAnimation. The scroll scrubbing is identical because the player exposes the same API either way.

Because lottie-web treats an animated keyframe with no i/o easing tangents as a hold keyframe — it never interpolates, so a trim end keyframed 0 to 100 stays stuck at 0 and the line never draws. The helper functions in this snippet attach linear tangents (control points at 0.5/0.5) to every keyframe, which is what makes the value actually move. If you hand-edit a keyframe and the animation goes blank, missing tangents are the first thing to check.

The trim end and the dot both advance linearly over the same 120 frames, so the drawn fraction at any frame is simply frame / totalFrames. The snippet samples the wave function at regular frames and keyframes the dot position to those points, so the dot sits on the leading edge of the drawn stroke throughout. If you reshape the line, regenerating the dot keyframes from the same function keeps them in sync.

play runs the animation on its internal clock, which is exactly what you do not want when scroll should control it. goToAndStop(frame, true) renders one specific still frame and never starts the timer — the second argument tells lottie-web the value is a frame number, not milliseconds. Multiplying scroll progress by totalFrames gives the frame to show, and fractional frames interpolate smoothly so the draw is continuous.

Yes. Click JSX for a React component, Vue for a Vue 3 SFC, Angular for a standalone component, or Tailwind for a React + Tailwind version. Call lottie.loadAnimation against a ref inside a mount effect, register the ScrollTrigger there, and on cleanup call anim.destroy() and kill the ScrollTrigger instance (or revert a gsap.context) so the SVG and scroll listener are released on unmount.