• About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us
AimactGrow
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing
No Result
View All Result
AimactGrow
No Result
View All Result

Constructing Responsive, Scroll-Triggered Curved Path Animations with GSAP

Admin by Admin
December 17, 2025
Home Coding
Share on FacebookShare on Twitter


One of many hero designs we got here up with for Method 1 driver Lando Norris’s new web site had an attention-grabbing problem: animating a component alongside a easy curved path between a number of mounted positions, one that may work throughout any gadget dimension. Whereas GSAP’s MotionPath plugin makes path-based animation easy, we would have liked one thing extra dynamic. We wanted a system that would recalculate its curves responsively, adapt to completely different layouts, and provides us exact management over the trail’s form throughout growth.

On this tutorial, we’ll stroll via constructing a scroll-triggered curved path animation with a visible configurator software that permits you to dial within the good curve by dragging management factors in real-time.

Instruments Used:

Paths & Management Factors demo ↗


Free GSAP 3 Express Course


Be taught fashionable net animation utilizing GSAP 3 with 34 hands-on video classes and sensible tasks — good for all ability ranges.


Test it out

The Design Problem

The idea was easy: as customers scroll, a component ought to journey easily alongside a curved path between three particular positions on the web page, altering dimension because it strikes. The difficult half? Every place had completely different dimensions, the trail wanted to really feel pure and easy, and all the things needed to recalculate completely when the browser window resized.

Static SVG paths wouldn’t lower it. They’d break on completely different display sizes and couldn’t adapt to our responsive format. We wanted curves that had been calculated dynamically primarily based on precise factor positions.

Understanding Bezier Curves

Earlier than diving into code, let’s rapidly cowl the muse: cubic Bezier curves. These curves are outlined by 4 factors:

  1. Begin level (anchor)
  2. First management level (CP1) – “pulls” the curve away from the beginning
  3. Second management level (CP2) – “pulls” the curve towards the tip
  4. Finish level (anchor)

In SVG path syntax, this seems to be like:

M x1,y1 C cpx1,cpy1 cpx2,cpy2 x2,y2

The place M strikes to the beginning level, and C attracts a cubic Bezier curve utilizing two management factors.

For our animation between three positions, we’d like two curve segments, which suggests 4 management factors whole:

  • CP1 and CP2 for the primary curve (Place 1 → Place 2)
  • CP3 and CP4 for the second curve (Place 2 → Place 3)

Setting Up the HTML Construction

Our markup is deliberately minimal. We outline three place markers and one animated factor:

Place 1

Place 2

Place 3

The place components function invisible anchors. We’ll measure their middle factors to calculate our path. In manufacturing, these would probably be hidden or eliminated solely, with CSS positioning defining the place the animated factor ought to journey.

Calculating Dynamic Management Factors

First, we have to measure the place our anchor positions truly are on the web page:

perform getPositions() {
  const part = doc.querySelector('[data-section="hero"]');
  const pos1 = doc.querySelector('[data-pos="1"]');
  const pos2 = doc.querySelector('[data-pos="2"]');
  const pos3 = doc.querySelector('[data-pos="3"]');
  
  const rectSection = part.getBoundingClientRect();
  
  return [pos1, pos2, pos3].map((el) => {
    const r = el.getBoundingClientRect();
    return {
      x: r.left - rectSection.left + r.width / 2,
      y: r.high - rectSection.high + r.top / 2,
      width: r.width,
      top: r.top,
    };
  });
}

This perform returns the middle level of every place relative to our scroll part, together with their dimensions. We’ll want these for dimension interpolation later.

Now for the attention-grabbing half: mechanically calculating management factors that create easy S-curves. Right here’s our method:

perform calculateDefaultControlPoints(positions) {
  return [
    // CP1: Extends from position 1 toward position 2
    {
      x: positions[0].x,
      y: positions[0].y + (positions[1].y - positions[0].y) * 0.8,
    },
    // CP2: Approaches place 2 from above
    {
      x: positions[1].x,
      y: positions[1].y - Math.min(800, (positions[1].y - positions[0].y) * 0.3),
    },
    // CP3: Extends from place 2 towards place 3
    {
      x: positions[1].x,
      y: positions[1].y + Math.min(80, (positions[2].y - positions[1].y) * 0.3),
    },
    // CP4: Approaches place 3 from above
    {
      x: positions[1].x + (positions[2].x - positions[1].x) * 0.6,
      y: positions[2].y - (positions[2].y - positions[1].y) * 0.2,
    }
  ];
}

The magic is in these multipliers (0.8, 0.3, 0.6, 0.2). They management how “pulled” the curve is:

  • CP1 extends 80% of the vertical distance from place 1, conserving it horizontally centered to create a downward arc
  • CP2 sits above place 2, guaranteeing a easy vertical method
  • CP3 and CP4 work equally for the second curve phase

The Math.min() constraints forestall the management factors from extending too far on extraordinarily giant screens.

Constructing the SVG Path String

As soon as we now have our positions and management factors, we assemble an SVG path:

perform buildPathString(positions, controlPoints) {
  return `M${positions[0].x},${positions[0].y} ` +
    `C${controlPoints[0].x},${controlPoints[0].y} ` +
    `${controlPoints[1].x},${controlPoints[1].y} ` +
    `${positions[1].x},${positions[1].y} ` +
    `C${controlPoints[2].x},${controlPoints[2].y} ` +
    `${controlPoints[3].x},${controlPoints[3].y} ` +
    `${positions[2].x},${positions[2].y}`;
}

This creates a steady path with two cubic Bezier curves, forming our S-shape.

Animating with GSAP’s MotionPath

Now we hand this path to GSAP. The MotionPath plugin does the heavy lifting of calculating positions alongside our curve:

const pathString = buildPathString(positions, controlPoints);

gsap.set(img, {
  x: positions[0].x,
  y: positions[0].y,
  width: positions[0].width,
  top: positions[0].top,
});

const tl = gsap.timeline({
  scrollTrigger: {
    set off: part,
    begin: 'high high',
    finish: 'backside backside',
    scrub: true,
    invalidateOnRefresh: true,
  },
});

tl.to(img, {
  period: 1.5,
  motionPath: {
    path: pathString,
    autoRotate: false,
  },
  ease: 'none',
  onUpdate: perform () {
    // Dimension interpolation logic right here
  },
});

Key factors:

  • scrub: true: Ties the animation progress on to scroll place
  • invalidateOnRefresh: true: Ensures paths recalculate when the window resizes
  • ease: ‘none’: Linear development provides us predictable scroll-to-position mapping
  • transformOrigin: ‘50% 50%’: Facilities the factor on the trail

Various enter: array-based paths

GSAP’s MotionPath plugin also can construct paths straight from level information, fairly than a full SVG path string. You may move an array of anchor and control-point coordinates and let GSAP generate the cubic Bezier internally.

You may see a minimal demo displaying this method in motion right here: https://codepen.io/GreenSock/pen/raerLaK

In our case, we generate the SVG path explicitly so we are able to visualise and debug it within the configurator, however for easier setups this array-based syntax is usually a light-weight different.

Interpolating Dimension Alongside the Path

As our factor travels alongside the trail, we would like it to easily transition from every place’s dimensions to the subsequent. We deal with this within the onUpdate callback:

onUpdate: perform () {
  const progress = this.progress();
  
  // First half: interpolate between place 1 and place 2
  if (progress <= 0.5) {
    const normalizedProgress = progress * 2;
    const width = positions[0].width + 
      (positions[1].width - positions[0].width) * normalizedProgress;
    const top = positions[0].top + 
      (positions[1].top - positions[0].top) * normalizedProgress;
    img.fashion.width = `${width}px`;
    img.fashion.top = `${top}px`;
  } 
  // Second half: interpolate between place 2 and place 3
  else {
    const normalizedProgress = (progress - 0.5) * 2;
    const width = positions[1].width + 
      (positions[2].width - positions[1].width) * normalizedProgress;
    const top = positions[1].top + 
      (positions[2].top - positions[1].top) * normalizedProgress;
    img.fashion.width = `${width}px`;
    img.fashion.top = `${top}px`;
  }
}

We cut up the animation on the 50% mark (after we attain place 2), then normalise the progress for every phase (0-1 for every half), giving us easy dimension transitions that align with the trail.

Constructing the Visible Configurator

Right here’s the place issues get attention-grabbing for growth workflow. Auto-calculated management factors are a terrific place to begin, however each design is completely different. We have to fine-tune these curves, however adjusting multipliers in code and refreshing the browser will get tedious quick.

As a substitute, we constructed a visible configurator that lets us drag management factors and see the leads to real-time.

Creating the Debug Overlay

We create an SVG overlay that sits above our animated factor:

const debugSvg = doc.createElementNS('http://www.w3.org/2000/svg', 'svg');
debugSvg.fashion.place = 'absolute';
debugSvg.fashion.high = 0;
debugSvg.fashion.left = 0;
debugSvg.fashion.width = '100%';
debugSvg.fashion.top = '100%';
debugSvg.fashion.pointerEvents = 'none';
debugSvg.fashion.zIndex = 15;
part.appendChild(debugSvg);

Then we add visible components:

// The trail itself (pink line)
const debugPath = doc.createElementNS('http://www.w3.org/2000/svg', 'path');
debugPath.setAttribute('stroke', '#ff0040');
debugPath.setAttribute('stroke-width', '3');
debugPath.setAttribute('fill', 'none');
debugSvg.appendChild(debugPath);

// Anchor factors (pink circles at positions 1, 2, 3)
for (let i = 0; i < 3; i++) {
  const circle = doc.createElementNS('http://www.w3.org/2000/svg', 'circle');
  circle.setAttribute('r', '8');
  circle.setAttribute('fill', '#ff0040');
  debugSvg.appendChild(circle);
  anchorPoints.push(circle);
}

// Management factors (inexperienced circles - these are draggable)
for (let i = 0; i < 4; i++) {
  const circle = doc.createElementNS('http://www.w3.org/2000/svg', 'circle');
  circle.setAttribute('r', '8');
  circle.setAttribute('fill', '#00ff88');
  circle.setAttribute('class', 'svg-control-point');
  circle.fashion.pointerEvents = 'all'; // Allow interplay
  circle.dataset.index = i;
  debugSvg.appendChild(circle);
  controlPointElements.push(circle);
}

// Deal with strains (dashed strains connecting controls to anchors)
for (let i = 0; i < 4; i++) {
  const line = doc.createElementNS('http://www.w3.org/2000/svg', 'line');
  line.setAttribute('stroke', '#00ff88');
  line.setAttribute('stroke-dasharray', '4,4');
  debugSvg.appendChild(line);
  handleLines.push(line);
}

This provides us an entire visible illustration of our Bezier curve construction, one thing you’d see in vector enhancing software program like Illustrator or Figma.

Making Management Factors Draggable

The drag interplay is simple: observe mouse/contact place and replace the management level coordinates:

let isDragging = false;
let currentDragIndex = -1;

perform startDrag(e) {
  const goal = e.goal;
  if (goal.classList.comprises('svg-control-point')) {
    isDragging = true;
    currentDragIndex = parseInt(goal.dataset.index);
    goal.classList.add('dragging');
    e.preventDefault();
  }
}

perform drag(e) {
  if (!isDragging || currentDragIndex === -1) return;
  
  const rectSection = part.getBoundingClientRect();
  const clientX = e.clientX || (e.touches && e.touches[0].clientX);
  const clientY = e.clientY || (e.touches && e.touches[0].clientY);
  
  const newX = clientX - rectSection.left;
  const newY = clientY - rectSection.high;
  
  // Replace the management level
  currentControlPoints[currentDragIndex] = { x: newX, y: newY };
  
  // Rebuild the visualization and animation
  updateVisualization();
  buildAnimation();
}

perform endDrag() {
  if (isDragging) {
    const circles = debugSvg.querySelectorAll('.svg-control-point');
    circles.forEach(c => c.classList.take away('dragging'));
    isDragging = false;
    currentDragIndex = -1;
  }
}

debugSvg.addEventListener('mousedown', startDrag);
doc.addEventListener('mousemove', drag);
doc.addEventListener('mouseup', endDrag);

Whenever you drag a management level, we:

  1. Replace its place within the currentControlPoints array
  2. Rebuild the trail string
  3. Kill and recreate the GSAP animation with the brand new path
  4. Replace all visible components

This provides on the spot visible suggestions as you modify the curve.

Exporting Closing Values

When you’ve dialed within the good curve, you’ll need these management level values for manufacturing:

perform copyValues() {
  const valuesText = currentControlPoints.map((cp, i) => 
    `const controlPoint${i + 1} = {n  x: ${Math.spherical(cp.x)},n  y: ${Math.spherical(cp.y)}n};`
  ).be a part of('nn');
  
  navigator.clipboard.writeText(valuesText);
}

This codecs the coordinates as JavaScript constants you may paste straight into your manufacturing code.

Dealing with Responsiveness

Right here’s the place our dynamic method pays off. When the window resizes:

let resizeTimeout;
window.addEventListener('resize', () => {
  clearTimeout(resizeTimeout);
  resizeTimeout = setTimeout(() => {
    positions = getPositions();
    updateVisualization();
    buildAnimation();
  }, 200);
});

We recalculate positions, rebuild the trail, and recreate the animation. The management level coordinates stay the identical (they’re already within the coordinate house of the scroll part) so the curve form adapts proportionally to the brand new format.

That is essential for responsive design. The identical curve construction works whether or not you’re on a cellphone, pill, or ultra-wide monitor.

A Be aware on GSAP’s MotionPathHelper

It’s value mentioning that GSAP features a plugin referred to as MotionPathHelper that gives related visible enhancing capabilities for MotionPath animations. Should you’re working with extra complicated path eventualities or want options like path enhancing with a number of curves, MotionPathHelper is value exploring.

For our use case, we needed tight integration with our scroll-triggered animation and a workflow particularly tailor-made to our three-position setup, which is why we constructed a customized answer. However for those who’re on the lookout for a ready-made path editor with broader capabilities, MotionPathHelper is a wonderful possibility.

Accessibility

For customers preferring diminished movement, we must always respect their system preferences. Whereas we are able to use JavaScript’s native matchMedia API, GSAP supplies its personal matchMedia utility that integrates seamlessly with its animation system:

// Utilizing GSAP's matchMedia
gsap.matchMedia().add("(prefers-reduced-motion: scale back)", () => {
  // Skip the curved path animation solely
  gsap.set(img, {
    x: positions[2].x, // Leap to last place
    y: positions[2].y,
    width: positions[2].width,
    top: positions[2].top,
  });
  
  return () => {
    // Cleanup perform (non-obligatory)
  };
});

gsap.matchMedia().add("(prefers-reduced-motion: no-preference)", () => {
  // Run the complete animation
  buildAnimation();
  
  return () => {
    // Cleanup perform (non-obligatory)
  };
});

GSAP’s matchMedia presents benefits over the native API: it mechanically manages cleanup when media queries change, integrates higher with GSAP’s animation lifecycle, and supplies a constant API for all responsive behaviors. This instantly locations the factor at its last place for customers who’ve indicated they like diminished movement, whereas working the complete animation for everybody else.

*(Be aware: We didn’t implement this on the reside Lando Norris website 😬, however it’s undoubtedly a finest follow value following.)*

Manufacturing Workflow

Our growth workflow seems to be like this:

  1. Preliminary Setup: Place the anchor components the place you need them utilizing CSS
  2. Auto-Calculate: Let the default management factors offer you a beginning curve
  3. Advantageous-Tune: Open the configurator, drag management factors till the curve feels proper
  4. Export: Copy the ultimate management level values
  5. Deploy: Substitute the auto-calculated management factors together with your customized values
  6. Clear Up: Take away the configurator code and debug visualisation for manufacturing

In manufacturing, you’d sometimes hard-code the management factors and take away all of the configurator UI:

const controlPoints = [
  { x: 150, y: 450 },
  { x: 800, y: 800 },
  { x: 850, y: 1200 },
  { x: 650, y: 1400 }
];

// Use these straight as a substitute of calculateDefaultControlPoints()

Wrapping Up

Constructing this scroll-triggered curved path animation taught us a beneficial lesson about balancing automation with management. Auto-calculated management factors offer you a terrific place to begin, however being able to visually refine them makes all of the distinction in attaining that good curve.

The mixture of GSAP’s highly effective MotionPath plugin, ScrollTrigger for scroll-syncing, and a customized visible configurator gave us precisely what we would have liked: a responsive animation system that appears nice on any gadget and a growth workflow that doesn’t contain guessing at coordinates.

For the Lando Norris web site, this method allowed us to create a hero animation that feels easy, intentional, and completely tailor-made to the design whereas staying absolutely responsive throughout units.

Tags: AnimationsBuildingCurvedGSAPpathResponsiveScrollTriggered
Admin

Admin

Next Post
20 Leaked Apple Merchandise You Ought to Look Ahead To In 2026

20 Leaked Apple Merchandise You Ought to Look Ahead To In 2026

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recommended.

Battlefield 6 casually confirms open beta, and a possible answer to that entire unlocked weapons state of affairs

Battlefield 6 casually confirms open beta, and a possible answer to that entire unlocked weapons state of affairs

July 22, 2025

הסוכנויות הכי טובות לפרסום בטלגרם

April 1, 2025

Trending.

AI-Assisted Menace Actor Compromises 600+ FortiGate Gadgets in 55 Nations

AI-Assisted Menace Actor Compromises 600+ FortiGate Gadgets in 55 Nations

February 23, 2026
How Voice-Enabled NSFW AI Video Turbines Are Altering Roleplay Endlessly

How Voice-Enabled NSFW AI Video Turbines Are Altering Roleplay Endlessly

June 10, 2025
Introducing Sophos Endpoint for Legacy Platforms – Sophos Information

Introducing Sophos Endpoint for Legacy Platforms – Sophos Information

August 28, 2025
10 tricks to begin getting ready! • Yoast

10 tricks to begin getting ready! • Yoast

July 21, 2025
Rogue Planet’ in Growth for Launch on iOS, Android, Change, and Steam in 2025 – TouchArcade

Rogue Planet’ in Growth for Launch on iOS, Android, Change, and Steam in 2025 – TouchArcade

June 19, 2025

AimactGrow

Welcome to AimactGrow, your ultimate source for all things technology! Our mission is to provide insightful, up-to-date content on the latest advancements in technology, coding, gaming, digital marketing, SEO, cybersecurity, and artificial intelligence (AI).

Categories

  • AI
  • Coding
  • Cybersecurity
  • Digital marketing
  • Gaming
  • SEO
  • Technology

Recent News

Each Sport You Can Purchase That Comes With A Fortnite Pores and skin Or Equipment

Each Sport You Can Purchase That Comes With A Fortnite Pores and skin Or Equipment

February 27, 2026
High search engine optimization Ideas For 2026

High search engine optimization Ideas For 2026

February 27, 2026
  • About Us
  • Privacy Policy
  • Disclaimer
  • Contact Us

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved

No Result
View All Result
  • Home
  • Technology
  • AI
  • SEO
  • Coding
  • Gaming
  • Cybersecurity
  • Digital marketing

© 2025 https://blog.aimactgrow.com/ - All Rights Reserved