How one can Create Animated GIFs from GSAP Animations — SitePoint

How one can Create Animated GIFs from GSAP Animations — SitePoint

[ad_1]

On this article, I’m going to provide an explanation for how you’ll convert animations created the use of GSAP into animated GIFs the use of modern-gif.

Right here’s a sneak peek of 1 I made previous. 👇

How one can Create Animated GIFs from GSAP Animations — SitePoint

At the hyperlinks beneath, you’ll discover a are living preview and the entire code I’ll be referencing all the way through this text:

There are two “pages” within the repo. index incorporates the entire code for the GIF observed above, and easy is a place to begin for the stairs coated on this publish.

Desk of Contents

How one can convert GSAP Animations into GIFs

The process I’m the use of to transform a GSAP animation right into a GIF comes to shooting SVG knowledge on every “replace” of the Tween and writing it to an HTML canvas. After the Tween completes I’m then ready to transform SVG knowledge into Rasterized symbol knowledge which can be utilized by way of modern-gif to create every body of an animated GIF.

Getting Began

Right here’s the code I’ve used within the easy instance, and it’s what I’ll be the use of to provide an explanation for every of the stairs required to create an animated GIF from a GSAP animation:

<html lang='en'>
<head>
  <meta charset='utf-8' />
  <identify>Easy</identify>
  <script>
    const canvas = report.getElementById('canvas');
    const ctx = canvas.getContext('second');

    let animationFrames = [];
    let canvasFrames = [];

    gsap.timeline({
      onUpdate: () => {},
      onComplete: () => {},
    })
    .fromTo('#rect', { x: -50 }, { length: 2, x: 350, ease: 'energy.ease2' });
  </script>
</head>
<frame>
  <major>
    <phase>
      <svg
        identity='svg'
        xmlns='http://www.w3.org/2000/svg'
        viewBox='0 0 400 200'
        width={400}
        peak={200}
        taste={{ border: '1px cast purple' }}
      >
        <rect identity='rect' x='0' y='75' width='50' peak='50' fill='purple'></rect>
      </svg>
      <canvas identity='canvas' taste={{ border: '1px cast blue' }} width={400} peak={200}></canvas>
      <img identity='symbol' width={400} peak={200} taste={{ border: '1px cast inexperienced' }} />
      <a identity='hyperlink' obtain='easy.gif'>Obtain</a>
    </phase>
  </major>
  <script src='https://unpkg.com/modern-gif'></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js'></script>
</frame>
</html>

There are a few issues I’d like to provide an explanation for concerning the above code.

Inline Script

On the most sensible of the record I create a connection with the canvas component within the HTML (beneath) and outline a brand new connection with the canvas context known as ctx. This may occasionally permit me to reference the canvas component and write knowledge to it.

There are two arrays outlined to carry the captured knowledge (I’ll provide an explanation for the place every is utilized in a later step):

  • animationFrames
  • canvasFrames

And final, however now not least, an example of a GSAP Timeline and Tween that animates an SVG rect component within the HTML (beneath).

HTML

  • The HTML incorporates an svg component with an ID of svg with a purple rect component with an ID of rect. The rect is the component I’ll be animating.
  • Beneath the svg component is a canvas component. That is the place I’ll write the captured SVG knowledge to be used in a while.
  • Beneath the canvas component is an img component. That is the place the overall animated GIF will probably be displayed.
  • Finally, there’s an a component which can be utilized to “obtain” the GIF.

Script parts

The 2 script parts on the backside are for the modern-gif library and GSAP library. Each wish to be integrated within the web page so you’ll use them.

Shooting SVG Knowledge

Find the GSAP Timeline and make the next adjustments:

gsap.timeline({
  onUpdate: () => {
+    const xml = new XMLSerializer().serializeToString(svg);
+    const src = `knowledge:symbol/svg+xml;base64,${btoa(xml)}`;
+    animationFrames.push(src);
  },
  onComplete: () => {
+    console.log(animationFrames);
  },
})
.fromTo('#rect', { x: -50 }, { length: 2, x: 350, ease: 'energy.ease2' });

The above code serializes the HTML svg component and converts the knowledge to an svg+xml;base64 string. At this level, the “symbol knowledge” isn’t somewhat what I would like, however by way of changing it to a string I will be able to retailer it within the animationFrame array to be used in a while.

In case you’ve added the console.log within the onComplete serve as, you must see one thing very similar to the picture beneath within the console of your browser.

screenshot of svg+xml;base64 strings stored in an array and displayed in the browser's console

Convert SVG Knowledge to Rasterized Knowledge

gsap.timeline({
  onUpdate: () => {
    const xml = new XMLSerializer().serializeToString(svg);
    const src = `knowledge:symbol/svg+xml;base64,${btoa(xml)}`;
    animationFrames.push(src);
  },
  onComplete: () => {
-    console.log(animationFrames);
+    let inc = 0;
+    const renderSvgDataToCanvas = () => {
+      const virtualImage = new Symbol();
+      virtualImage.src = animationFrames[inc];
+      virtualImage.onload = () => {
+        ctx.clearRect(0, 0, 400, 200);
+        ctx.drawImage(virtualImage, 0, 0, 400, 200);
+        canvasFrames.push(canvas.toDataURL('symbol/jpeg'));
+        inc++;
+        if (inc < animationFrames.period - 1) {
+          renderSvgDataToCanvas();
+        } else {
+          console.log(canvasFrames);
+        }
+      };
+    };
+    renderSvgDataToCanvas();
  },
})
.fromTo('#rect', { x: -50 }, { length: 2, x: 350, ease: 'energy.ease2' });

This step is moderately extra concerned and calls for that I carry out an motion for every index of the animationFrames array.

Via the use of a recursive serve as, renderSvgDataToCanvas, I will be able to use the picture knowledge from the animationFrames array, write it to the canvas. Then, by way of the use of canvas.toDataURL('symbol/jpeg') I will be able to retailer rasterized knowledge of every body of the animation within the canvasFrames array.

In case you’ve added the console.log within the onComplete serve as, you must see one thing very similar to the beneath within the console of your browser. This time, alternatively, be aware the MIME form of the knowledge: as a substitute of svg+xml, it’s symbol/jpeg. That is vital for what I wish to do subsequent.

rasterized data

Convert Rasterized Knowledge to GIF

That is the final step and comes to passing every index of the canvasFrames array onto modern-gif.

gsap.timeline({
onUpdate: () => {
  const xml = new XMLSerializer().serializeToString(svg);
  const src = `knowledge:symbol/svg+xml;base64,${btoa(xml)}`;
  animationFrames.push(src);
},
onComplete: () => {
  let inc = 0;
  const renderSvgDataToCanvas = () => {
    const virtualImage = new Symbol();
    virtualImage.src = animationFrames[inc];
    virtualImage.onload = () => {
      ctx.clearRect(0, 0, 400, 200);
      ctx.drawImage(virtualImage, 0, 0, 400, 200);
      canvasFrames.push(canvas.toDataURL('symbol/jpeg'));
      inc++;
      if (inc < animationFrames.period - 1) {
        renderSvgDataToCanvas();
      } else {
-          console.log(canvasFrames);
+          generateGif();
      }
    };
  };
+    const generateGif = async () => {
+      const gif = watch for modernGif.encode({
+        width: 400,
+        peak: 200,
+        frames: canvasFrames.map((body) => {
+          go back { imageData: body, lengthen: 0 };
+        }),
+      });
+      const frames = watch for gif;
+      const blob = new Blob([frames], { kind: 'symbol/gif' });
+      const src = URL.createObjectURL(blob);

+      const symbol = report.getElementById('symbol');
+      const hyperlink = report.getElementById('hyperlink');

+      symbol.src = src;
+      hyperlink.href = src;
+    };
    renderSvgDataToCanvas();
  },
})
.fromTo('#rect', { x: -50 }, { length: 2, x: 350, ease: 'energy.ease2' });

The usage of modernGif.encode you’ll move an array of knowledge onto frames and outline a lengthen for every body, I’ve selected so as to add a lengthen of 0 seconds.

The following a part of the code offers with changing the modernGif.ecode knowledge and changing it to “but any other” MIME kind, this time symbol/gif.

As soon as I’ve a last “blob” of knowledge that represents my animated GIF I convert it to a URL after which set the src and href of the picture and hyperlink parts so I will be able to see and obtain the GIF within the browser.

Converting to GIF

Body Fee

You could realize the overall GIF runs somewhat slowly, it’s because animations that run within the browser will normally play again at 60 frames consistent with 2nd (fps), while GIFs normally run at a miles slower body price, 12 or 24fps.

To “drop” some frames of the animation I take advantage of an array filter out and JavaScript the rest operator to decide if the index is divisible by way of a undeniable quantity, in my case, I selected 6. Indexes that aren’t divisible by way of 6 are filtered out of the array. The ensuing animated GIF, whilst slightly clunky, will play again a lot quicker.

const generateGif = async () => {
  const gif = watch for modernGif.encode({
    width: 400,
    peak: 200,
    frames: canvasFrames
+       .filter out((_, index) => index % 6 === 0)
      .map((body) => {
        go back { imageData: body, lengthen: 0 };
      }),
    });
  const frames = watch for gif;
  const blob = new Blob([frames], { kind: 'symbol/gif' });
  const src = URL.createObjectURL(blob);

  const symbol = report.getElementById('symbol');
  const hyperlink = report.getElementById('hyperlink');

  symbol.src = src;
  hyperlink.href = src;
};

And that’s how you’ll move from GSAP SVG animation to animated GIF by the use of the HTML canvas!

You probably have any questions on anything else I’ve described on this publish be happy to search out me on Twitter/X: @PaulieScanlon.



[ad_2]

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back To Top
0
Would love your thoughts, please comment.x
()
x