Jump to content
Search Community

Animating masks with GSAP (clipPath, clip-path, SVG mask)

mvaneijgen test
Moderator Tag

Recommended Posts

SVG Mask

The most simple solution is to create a mask with SVG and adding the image to the SVG file it self. Although this is a simple solution it is probably not going to be bullet proof, because your images probably come from somewhere else and you’re not going to hand craft all these images inside your vector program, but I want to show that this is possible and is indeed the most simple solution.

 

See the Pen xxMBVqX by mvaneijgen (@mvaneijgen) on CodePen

 

CSS Clip-path

If you have a relative simple shape you could use a CSS clip-path to mask your shape. There are a few gotchas, but if you keep them in mind this will be the most robust option. Personally I use https://bennettfeely.com/clippy/ to create my clipPaths and the first gotcha is that you have to animate between shapes with the same amount of points (if you’re familiar with MorphSVG you know why this is). Another thing to keep in mind is that when animating complex strings with GSAP is that the strings should be as much the same as possible, see this example below

// Example, our starting string
polygon(50% 10%, 75% 17%, 98% 35%)
//  Bad, not the same amount of points and diffrent suffixes 
polygon(50% 0, 18% 12%, 66% 29px, 98% 35%)
//  Good, same amount of points and everyhting is suffexed with a % sign
polygon(50% 0%, 18% 12%, 66% 29%)


See the Pen MWLxyPp by mvaneijgen (@mvaneijgen) on CodePen

 

SVG Mask but on normal  tags

A really weird but really useful solution is creating an SVG that is 1px by 1px. Yep, you heard it write a 1x1 SVG. Everything with in the 0 - 1 pixel space will gets stretched over your image (if you give your clipPath the following tag clipPathUnits="objectBoundingBox”) and you’re golden, I’ve learned this from Dave Smyth over at https://davesmyth.com/clip-path-scaling where he has an even more in depth look on how and why this works, recommend giving it a read if you want to go this route!

 

See the Pen jOdJGQq by mvaneijgen (@mvaneijgen) on CodePen

 

Hope it helps and happy tweening! 

 

Some extra resources you could take a look at.

Organic Morphing: Getting needed points from Adobe Illustrator — motiontricks

SVG Masks and clipPaths — motiontricks

GreenSock SVG Ripple Mask Effect — creativecodingclub

Easy SVG Masking — creativecodingclub

Clip-path scaling — davesmyth.com

 

Extra example

With this last example you can create really elaborate effect with just a few simple shapes. The example below uses the exact same timeline animation for each of the clip paths with some clever use of the stagger object.

 

See the Pen bGQjVxq by mvaneijgen (@mvaneijgen) on CodePen

  • Like 5
  • Thanks 1
Link to comment
Share on other sites

Thanks for your generosity Mitchel, I know that this comes from knowledge you have gathered and mastered by answering countless questions on this subject.

 

As Toso mentions this will become a priceless guide for many users in this forums and an extremely valuable reference for everyone.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Nice job @mvaneijgen,

4 hours ago, mvaneijgen said:

A really weird but really useful solution is creating an SVG that is 1px by 1px. Yep, you heard it write a 1x1 SVG. Everything with in the 0 - 1 pixel space will gets stretched over your image (if you give your clipPath the following tag clipPathUnits="objectBoundingBox”)

 

The following may offer a less fuzzy understanding of the transform / coordinate system change when using objectBoundingBox. https://www.w3.org/TR/SVG/coords.html#ObjectBoundingBoxUnits

 

This converter should also be useful at times for deriving the needed [0,1] coordinates when using objectBoundingBox. Instead of squinting to design 1x1 artwork 🎨 😁https://yoksel.github.io/relative-clip-path/

 

Transform can also be used within SVG on 'appropriate items' when using objectBoundingBox and [0,1] coordinates. Utilizing the following basic math:

 

Formula:

1 / Width

1 / Height

 

Example / Output:

1 / 550 = 0.001818181818182

1 / 325 = 0.003076923076923

 

Then use appropriately in SVG:

transform="scale(0.001818181818182, 0.003076923076923)”

 

  • Like 3
  • Thanks 1
Link to comment
Share on other sites

  • 2 months later...
On 12/9/2023 at 9:03 AM, mvaneijgen said:

A really weird but really useful solution is creating an SVG that is 1px by 1px. Yep, you heard it write a 1x1 SVG. Everything with in the 0 - 1 pixel space will gets stretched over your image (if you give your clipPath the following tag clipPathUnits="objectBoundingBox”)

In case it's useful, I put together a helper function that'll normalize all the values inside a path so that they're between 0 and 1: 

function normalizePath(path) {
  path = gsap.utils.toArray(path);
  if (!path[0].hasAttribute("d")) {
    path = gsap.utils.toArray(path[0].children);
  }
  if (path.length > 1) {
    path.forEach(normalizePath);
    return path;
  }
  let _svgPathExp = /[achlmqstvz]|(-?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig, 
      _scientific = /[\+\-]?\d*\.?\d+e[\+\-]?\d+/ig,
      d = path[0].getAttribute("d"),
      a = d.replace(_scientific, m => { let n = +m; return (n < 0.0001 && n > -0.0001) ? 0 : n; }).match(_svgPathExp),
      nums = a.filter(n => !isNaN(n)).map(n => +n),
      normalize = gsap.utils.normalize(Math.min(...nums), Math.max(...nums)),
      finals = a.map(val => isNaN(val) ? val : normalize(+val)),
      s = "",
      prevWasCommand;
  finals.forEach((value, i) => {
    let isCommand = isNaN(value)
    s += (isCommand && i ? " " : prevWasCommand || !i ? "" : ",") + value;
    prevWasCommand = isCommand;
  });
  path[0].setAttribute("d", s);
  return path;
}

Usage

normalizePath("#mask")

So that'll make a path like this: 

<path d="M3903,6453.410182017132 L300,1.542786465904 L-10000,1481.542786465904 L-10000,6453.410182017132 Z"></path>

Into this: 

<path d="M0.8449920014268762,1 L0.6260100420554431,0.6078705068325081 L0,0.6978214643317369 L0,1 Z"></path>

I hope that helps somebody. 

  • Like 3
  • Thanks 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...