惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Know Your Adversary
Know Your Adversary
D
Docker
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
人人都是产品经理
人人都是产品经理
V
V2EX
V
Visual Studio Blog
J
Java Code Geeks
博客园 - 【当耐特】
罗磊的独立博客
量子位
W
WeLiveSecurity
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
The Cloudflare Blog
O
OpenAI News
PCI Perspectives
PCI Perspectives
The Last Watchdog
The Last Watchdog
S
Schneier on Security
博客园 - Franky
WordPress大学
WordPress大学
T
Tor Project blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Security Latest
Security Latest
Cisco Talos Blog
Cisco Talos Blog
腾讯CDC
美团技术团队
博客园 - 叶小钗
www.infosecurity-magazine.com
www.infosecurity-magazine.com
月光博客
月光博客
S
Secure Thoughts
Engineering at Meta
Engineering at Meta
T
Tailwind CSS Blog
TaoSecurity Blog
TaoSecurity Blog
Google DeepMind News
Google DeepMind News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Last Week in AI
Last Week in AI
aimingoo的专栏
aimingoo的专栏
G
Google Developers Blog
D
DataBreaches.Net
Project Zero
Project Zero
S
SegmentFault 最新的问题
C
Cisco Blogs
H
Help Net Security
Google Online Security Blog
Google Online Security Blog
A
About on SuperTechFans
F
Fortinet All Blogs
博客园 - 司徒正美

Codrops

The Art of Continuous Transformation: How Garden Eight Blends Integrity with Play | Codrops Building Cerebrium: Making Serverless Infrastructure Tangible | Codrops Building Ridgeline: Engineering a Real-Time 3D Experience in Webflow | Codrops Magnetic Commerce: Building the Dash Creative Website | Codrops The Craft Behind Memorable Digital Experiences: Inside Unseen Studio | Codrops ZERO: The Engineering Behind a Defiant Interactive Narrative | Codrops Meet the Speakers of the First Three.js Conference | Codrops The Architecture Behind Trionn: Coordinating GSAP, Three.js, Lenis, and Web Audio | Codrops Where Stories Become Interactive Worlds: How makemepulse Brings Ideas to Life Across Web, XR, and Beyond | Codrops The Sleepers: Creating an Atmospheric WebGL Experience with Lightweight Techniques | Codrops Building an Interactive Wave Propagation Cube Grid with Three.js | Codrops Ten Years Away: Designing an Interactive Comic for Studio375’s Tenth Anniversary | Codrops Building a Scroll-Driven 3D Gallery Using a Blender Camera Path with Three.js and GSAP | Codrops From Years of Client Work to a Next.js + Sanity Starter Kit | Codrops Sculpting a Digital Athlete: Capturing Stefanos Tsitsipas Beyond the Court | Codrops Building Persistent Page Transitions with WebGPU and Vanilla JavaScript | Codrops Inside Bisous: Designing an Editorial Experience for Cinematic CGI | Codrops Engineering the Web Experience Behind Shopify’s Spring ’26 Edition: Everywhere | Codrops Shaping Stories into Experience: The Work of Kevin Lam | Codrops Testing What Users Actually See with Vitest and Chromatic | Codrops Podium: Building a Website Where Running Becomes Storytelling | Codrops Designing Beyond the Surface: How DashDigital Turns Complexity into Clarity | Codrops Creative Entrepreneurship: Designing the Machine | Codrops Exploring 3D Image Rotations on Scroll | Codrops Always Building, Always Learning: Cyd Stumpel’s Journey Through the Modern Web | Codrops Designing A Better Lou: Reducing Cognitive Load Through Design, Content, and Systems | Codrops Sketching the Impossible: A 3D Portfolio Built Without a Single 3D Model | Codrops Building Horeca: Advanced Motion Design in Webflow Without the Performance Trade-Offs | Codrops Building an Interactive Digital Stamp Collection with Shaders, Postcards, and Playful Inspection | Codrops No Two Paths Alike: Inside San Rita’s Approach to Digital Experiences | Codrops The Making of the New Lesse Studio Website: Clarity, Performance, and Intentionality | Codrops Creating a Thumbnail Flow Animation with GSAP MotionPath | Codrops Forging Her Own Path: Houmahani Kane’s Journey in Creative Development | Codrops Beaucoup and the Pursuit of Memorable Experiences | Codrops The Future of Emotional Technology: Comfort Websites for Growth and Self-Awareness | Codrops The Never Ending Story: Building a Seamless Infinite Scroll Experience with GSAP & Lenis | Codrops Whooshes, Snaps and Shaders: Adrien Vanderpotte and the Feeling of the Interface | Codrops Building a Scroll-Driven 3D Cube Gallery in Webflow with GSAP | Codrops Made With Gsap: Building a Fun Gravity-Based Mouse Trail | Codrops 80s Business Tech and Seamless Scene Transitions: Inside Shader.se’s Scroll-Driven WebGPU Pipeline | Codrops Merlin: The Code Boutique Turning Motion Into Digital Magic | Codrops Designing Ourselves: The New Obys Identity and Website | Codrops Exploring the HTML-in-Canvas Proposal | Codrops Le:mma Studio: Building the Feeling Behind the Screen | Codrops From Shader Uniforms to Clip-Path Wipes: How GSAP Drives My Portfolio | Codrops Reverse-Engineering Claude AI’s Mascot Animations with SVG and GSAP | Codrops Akaru: Crafting Precision-Driven Digital Experiences | Codrops Designing Against the Gallery: A Two-Year Journey to a Layered Portfolio Experience | Codrops Between Human and Machine: Sofia Papadopoulou’s Approach to Augmented Creativity | Codrops More Than a Portfolio: Building a Scroll-Driven 3D World with Something to Say | Codrops Rhumb Studio: Small but Mighty, Shaped by Curiosity | Codrops Susurrus: Crafting a Cozy Watercolor World with Three.js and Shaders | Codrops Building 4WIDE: Turning Distortion, Blur, and Motion into a Coherent Experience | Codrops A Playful Clip Menu with GSAP’s easeReverse | Codrops False Earth: From WebGL Limits to a WebGPU-Driven World | Codrops Interactive Storytelling for the Web: Building Immersive Stories with Timelines, 3D, and Layered Scenes | Codrops The Art of Complex Motion: Corentin Bernadou’s World of Shaders and Experimentation | Codrops They Call Me Giulio: The Making of a Cinematic Cyberpunk Portfolio | Codrops Lusion: Where Digital Craft Meets Ambitious Experimentation | Codrops The Exat Microsite: Pushing a Typography Showcase to New Creative Extremes | Codrops A Single DM, a First SOTD, and the Start of Chanh M. Ho’s Creative Journey | Codrops Creating Custom Page Transitions in Astro with Barba.js and GSAP | Codrops R—K ’26: The Thinking and Code Behind a Portfolio Led by Presence | Codrops Building the Maxima Therapy Website: React, GSAP, and Dabbling with AI | Codrops Where Engineering Meets Craft: Edoardo Lunardi’s Obsession with the Details | Codrops Animating 160,000 Cubes in Three.js to Visualize Dithering | Codrops Arnaud Rocca’s Portfolio: From a GSAP-Powered Motion System to Fluid WebGL | Codrops Where Confidence Needs No Decoration: The Malvah.Studio Story | Codrops Motion Highlights #17 | Codrops
Creating Scroll-Driven SVG Map Animations with GSAP | Codrops
By Tom Miller · 2026-05-21 · via Codrops

This tutorial will show you how to build an animated map using SVG and GSAP.js. The goal is to create an eye-catching interaction that is uncomplicated, lightweight, and doesn’t require the use of a third-party map API.

The Setup

We’ll use an SVG element to create our responsive stage. It contains:

  • a map image,
  • a path,
  • circles marking the start and end of the route,
  • and two groups for “camera” movement

GSAP draws the path, moves our point-of-view, and ties our timeline progress to scroll position. For this, you’ll need to include the following scripts:

  • gsap.min.js
  • ScrollTrigger.min.js
  • DrawSVGPlugin.min.js
  • MotionPathPlugin.min.js

Here’s a minimal demo with all of this working together.

Let’s break down the HTML and CSS before walking through the JS:

<section id="s1"> (scroll down) </section>

<section id="s2">
  <svg class="map" viewBox="0 0 1500 1500" preserveAspectRatio="xMidYMid slice">
    <g class="pov">
      <g fill="#fff" stroke="#223e6b" stroke-width="2" stroke-linejoin="round">
        <image href="https://assets.codepen.io/721952/chs_map.jpg" width="100%" height="100%"/>
        <path class="path" fill="none" stroke-width="3.3" d="m742 937 18-52 2-28 2-25-26 4-1-24-41 8-37 4-51 5 10 20 3 26 99-13-3-35"/>
        <circle class="dot-start" r="4" cx="742" cy="937"/>
        <circle class="dot-end" r="4"/>
      </g>
    </g>
  </svg>
</section>

<section id="s3"> (scroll up) </section>
html, body {
  margin:0;
  padding:0;
  font-family: "Open Sans", sans-serif;
  overscroll-behavior: none;
}

section {
  position:relative;
  left:0;
  top:0;
  width:100%;
  height:33vh;
  display:flex;
  align-items:center;
  justify-content:center;
}

#s2 {
  height:300vh;
}

.map {
  position:absolute;
  top:0;
  width:100vw;
  height:100vh;
}

We’ve got sections surrounding the SVG element just to give us some vertical scroll distance. To make the SVG responsive, we use the viewBox and preserveAspectRatio attributes. The former defines x/y coordinates and width/height aspect ratio for drawing the graphics. The latter sets the method for scaling and cropping. Actual width and height are applied in the CSS, and our SVG will fill the space accordingly.

To keep the code concise, several styling attributes are applied at the group-level and overwritten as needed. The path data was created by drawing over the map image in Illustrator, but you can use any SVG editor, or even code it by hand in the browser.

Lastly, we have circle elements, ‘.dot-start’ and ‘.dot-end’ to embellish the look of our route. The starting one has fixed cx and cy positioning, which matches the x and y values defined at the start of our path’s d attribute. “.dot-end” will be positioned dynamically in our JS. Speaking of…

gsap.timeline({
  scrollTrigger:{
    trigger: '#s2',
    start: '0 0',
    end: '100% 100%',
    pin: '.map',
    scrub:  1
  }
}) 
.from('.path', { drawSVG: '0 0' }, 0)
.to('.dot-end', { motionPath: '.path', immediateRender: true }, 0)

gsap.set('.pov', { x: 750, y: 750, scale: 2.5 })

gsap.set('.pov g', {
  x: -gsap.getProperty('.dot-end', 'x'),
  y: -gsap.getProperty('.dot-end', 'y')
})

We’ve created a timeline that scrubs along with the scroll progress of the section wrapping our SVG element. We are also pinning the SVG element while the timeline progresses. There are two, concurrent tweens in our timeline: one drawing the stroke of our path, and one moving the end circle along that path. 

Notice we are forcing an immediate render of the end circle, and not waiting for the user’s scroll progress to start the timeline. This is necessary because that circle’s dynamically determined x/y position will factor into how we center our point-of-view. First the outer group is pushed to the center of the stage, where we can also set the scale to zoom in/out as desired. Then the inner group is shifted left and up using the inverse x/y position of the end circle, effectively moving everything to the center.

Moving the “Camera”

Now that we’ve established a solid foundation, let’s add some “camera” movement. To do this, we’ll create two gsap.quickTo() functions. These will tween the x/y position of our inner group based on the location of the end circle. It’s important to use quickTo() instead of gsap.to() because quickTo() is optimized to run frequently, and we are going to call these each time our timeline updates.

Let’s also add another layer of scroll-tethered motion by tweening the scale of our map. Rather than setting it once, adding a .fromTo() tween to our timeline allows us to set the outer group’s initial values and tween the scale over the course of our timeline’s progress.

Here’s the updated code:

const xTo = gsap.quickTo('.pov g', 'x', {duration:1, ease:'expo'});
const yTo = gsap.quickTo('.pov g', 'y', {duration:1, ease:'expo'});

gsap.timeline({
  scrollTrigger:{
    trigger: '#s2',
    start: '0 0',
    end: '100% 100%',
    pin: '.map',
    scrub:  1
  },
  onUpdate:()=>{ // Move inner group using the inverse position of dot-end
    xTo(-gsap.getProperty('.dot-end', 'x'));
    yTo(-gsap.getProperty('.dot-end', 'y'));
  }
}) 
.from('.path', { drawSVG: '0 0' }, 0)
.to('.dot-end', { motionPath: '.path', immediateRender: true }, 0)
.fromTo('.pov', { x: 750, y: 750, scale: 2.5 }, { scale: 4, ease:'power1.inOut' }, 0)

gsap.set('.pov g', {
  x: -gsap.getProperty('.dot-end', 'x'),
  y: -gsap.getProperty('.dot-end', 'y')
})

And here’s the enhanced demo.

Taking it Further

At this point, we’ve created a versatile setup that you can easily modify and extend. To start exploring your own customization, try changing the map image and drawn path. Instead of a map route, it could show the flow of nutrients in a plant diagram, or draw a squiggly arrow around and through your travel photos.

You could also add to the scroll-triggered timeline; more zooming in and out, playing with rotation, drawing multiple paths are just a few ideas that come to mind. The important thing is to position additional tweens with intention. The above demos have concurrent tweens with matching durations, but ultimately you might want some parts to begin sooner or finish later. Planning out and playing with the timeline is an iterative process, but a nice side effect of our setup is the ability to scrub forward and backward as much as you like.

Below are a few additional explorations to inspire you to make your own scrolling SVG scene: