Animated Background SVG


Uncategorized

Updated Aug 27th, 2022

Sources to Find, Buy, Download, Use

Loading.io

Inspiration

The GitHub globe, article from their team here. And of course this is one of the first lines: “At the most fundamental level, the globe runs in a WebGL context powered by three.js.” This thing is so much more in depth that I thought it was.

More SVG animations here, not necessarily bg images.

And here and here and here.

The Portfolio on JS Mastery has a component of animated paths. There are 7 little zippy things that traverse some vector paths at variable speeds. There are 4 orange, 2 blue and one purple. some of the zips are on the same path and going faster than another so may pass. The paths are like a basket weave and can be seen as thing gray lines but have a radial mask with opacity for the outer edges. Overall the SVG can be seen behind some text which really adds to the basic text hero. It is in view on mobile until the 640px breakpoint (seen at 641px). Ran into some headaches here related to the gradient but also not having the electron on the circle but inside of it. Try setting the position to 0, 0. Saw this in original with the circle showing as only a quarter filled. There’s a pretty lengthy article here that was on CSS tricks that talks about the importance of having the element you are going to animate on a path originally be set to 0, 0 or else it will behave unexpectedly. A lot of work for something that is not even seen on mobile

It’s All in the Handbook

The AnimateMotion element

The mpath sub element

Other Sources

Sarah Drasner is the authority in the SVG animation space. Relatively recent video here to watch with time.

SVGOMG (SVG compression)

Competing Strategies

GSAP (greensock), Framer Motion, React Spring, D3.js, SVGator.

Your Image Editing Software Plays an Important Role

Artboard width and height will become “viewbox.” Will want to delete the “width” and “height” attributes and values on the root SVG element. I’ve heard you want the viewbox to be as small as possible but for this projects we used 602 x 602px since that was the source. May sure for the containing artboard, the clip-content box is checked on the top-right. Ensure the “fill” attribute is set to “none” on the SVG as well, so you can blend in nicely with whatever the background is.

Flatten Your Paths

A crucial element is that, you need to “flatten” your paths (The “Ctrl + e” shortcut works but there is no icon or change to know this is done until you see the code).

Position Elements Appropriately

Another crucial element is that you need to have the items you plan on animating have their center/anchor point at 0, 0. Not doing this can have the item you are animating still animate but not in the center of the path, (May be a circle within a circle). For Lines acting like a tail have the right-most-vertex be on the 0, 0 mark. In addition, make sure you are set up to have your animation stay within the “viewbox” if that is your intention. If you have an 8px circle animated on a path that is 2px from the edge, the circle will get cut off in the browser.

Note: The example project used sort of a “comet head and tail” approach where the head was a 2px ellipse that had a solid fill color and the tail was a 15px or 25px line with a linear gradient to make it look like “fire.”

Gradients

The paths that acted as the “track” got a radial gradient. The lines that acted as a “tail” got a linear gradient. Setting a non-black color you will see the “stop-color” show up in the code. The gradients will show up inside the “defs” SVG element and will be auto-linked to the element using it using the “url(#autoGenIdForGradient)” this is helpful. Something to consider for using a linear gradient on a line, make sure the line has height and width. Not sure what this is all about but the element needed width and height to get the desired effect. The example had a line diagonally in a bounding box and I could not recreate this. Using the pen tool gave me a bouncing box but the line was on the side and not diagonal. Experiment with using a rectangle with fill gradient instead.

Note: Gradients have always been a bit mysterious to me. in the SVG code both stops should have a “stop-color” and the offset is typically 0 and 1 although “0.33” is a common value as well. The “stop-opacity” of zero is typically on the bottom stop with the “offset” of 1.

Opacity

This is simple to add/change in the SVG code but for more complex projects be aware of the setting.

On Export

Don’t forget to hit the little settings button to make sure to “include id” and may also want to not see the fill on the artboard if there is one so uncheck that box. Also be aware that the layer order is reversed on export meaning whatever layer that was on the bottom in Figma will be on the top in the code. This is good to know for when you are naming your layers.

Once In The Code

Remove the width and height from the main SVG tag. May need to clean up an clip-mask. On the elements that are going to be animated on the path we need to convert the self-closing “path” tags to closing. We then paste in a “animateMotion” tag that looks something like this:

<animateMotion dur="5s" begin="0" repeatCount="indefinite" rotate="auto">
  <mpath xlinkHref="#path_1" />
</animateMotion>

The “mpath” is what “hooks up” or maps the element to the path you want it to animate on. The default for begin is 0 so that is just in there for an example. There are some other attributes to check out in the docs as well, (keypoints and keytimes, form and to and more).

How The SVG Is Placed Inside of a NextJS App

The SVG code is put inside a component’s function down in the JSX. This means stop-color needs to be “StopColor” and the same for opacity and a few other properties.

const BackgroundAnimation = () => (
  <div>
    <svg>
      // inline SVG code here
    </svg>
  </div>
)

export default BackgroundAnimation

Note: I am unsure at this point as to why parenthesis are used instead of curly brackets here, may have something to do with styled-components.

The component is rendered in the “index.js” file:

    <Layout>
      <Section grid>
        <Hero />
        <BgAnimation />
      </Section>
      <Projects />

      <Acomplishments />
    </Layout>

The “grid” prop passed to the section breaks the section into two halves using “1fr 1fr” although the text from the left half intentionally overflows in to the right half. What allows this to happen? Inside the “Hero” component, nested a few elements in, is an “H2 Section-Title” that has a “width: max-content” property. My mind is blown as I’ve never heard of this before.

In the example app the SVG was not visible on mobile until the browser reached 641px at the “sm” breakpoint, (Mobile first is my preference but the application is not set up this way). It’s pretty cool to see how styled-components uses breakpoints.

sm: screen and (max-width: 640px)

But what selector and property actually hides the SVG on mobile screens? On the “Section” just inside the “Section grid” parent, (the Section that starts the “Hero” component), inside the media query above you will see “width: calc(100vw -32px).” It is this, maybe in combination with “overflow: hidden” that is preventing the SVG from being seen on small screens, (the containing “div” is still there it is just has zero for width and height values when seen in the developer tools). Here’s a high-level look at the “Hero” component:

<Section row padding>
  <LeftSection>
   // section title, text, and a button
  </LeftSection>
</Section>

The colors: used in the project:

#13ADC7 // teal-ish

#945DD6 // purple

#F467373 // orange color

There is another post here with more details from deep diving through the project and a look at the technique overall.

Here is my custom version of the BGAnimation leveraging the technique learned:

    <svg viewBox="0 0 602 602" fill="none" xmlns="http://www.w3.org/2000/svg">
      <g opacity="0">
        <path id="basicStar" d="M467.053 22.0837C474.951 15.6999 486.234 23.789 482.723 33.3179L411.338 227.068C409.725 231.448 411.356 236.361 415.268 238.907L588.34 351.517C596.852 357.055 592.645 370.286 582.498 369.891L376.171 361.872C371.507 361.691 367.338 364.76 366.126 369.268L312.51 568.667C309.873 578.474 295.99 578.562 293.229 568.789L237.098 370.083C235.829 365.591 231.621 362.575 226.96 362.815L20.7512 373.441C10.6096 373.963 6.23617 360.787 14.6774 355.142L186.312 240.354C190.192 237.759 191.761 232.825 190.092 228.466L116.264 35.6335C112.633 26.1498 123.813 17.9187 131.791 24.2023L293.999 151.965C297.666 154.853 302.843 154.821 306.473 151.886L467.053 22.0837Z" stroke="url(#paint0_radial)" />
        <path id="crazyStar" d="M301 18L305.904 184.13C307.1 224.66 355.617 244.757 385.122 216.943L506.061 102.939L392.057 223.878C364.243 253.383 384.34 301.9 424.87 303.096L591 308L424.87 312.904C384.34 314.1 364.243 362.617 392.057 392.122L506.061 513.061L385.122 399.057C355.617 371.243 307.1 391.34 305.904 431.87L301 598L296.096 431.87C294.9 391.34 246.383 371.243 216.878 399.057L95.939 513.061L209.943 392.122C237.757 362.617 217.66 314.1 177.13 312.904L11 308L177.13 303.096C217.66 301.9 237.757 253.383 209.943 223.878L95.939 102.939L216.878 216.943C246.383 244.757 294.9 224.66 296.096 184.13L301 18Z" stroke="url(#paint1_radial)" />
        <path id="ellipse1" d="M336.711 335.711C189.527 482.895 54.3816 586.382 34.8553 566.855C15.3291 547.329 118.816 412.184 266 265C413.184 117.816 548.329 14.3291 567.855 33.8553C587.382 53.3816 483.895 188.527 336.711 335.711Z" stroke="url(#paint2_radial)" />
        <path id="ellipse2" d="M336.711 265C483.895 412.184 587.382 547.329 567.855 566.855C548.329 586.382 413.184 482.895 266 335.711C118.816 188.527 15.3291 53.3816 34.8553 33.8553C54.3816 14.3291 189.527 117.816 336.711 265Z" stroke="url(#paint3_radial)" />
        <path id="newBlob3" d="M298.952 395.247C311.13 547.637 96.2042 662.378 40.4997 541.363C-30.8248 386.414 105.912 259.158 250.003 127.221C394.094 -4.7162 491.586 40.4846 526.077 94.0536C603.417 214.173 278.394 137.978 298.952 395.247Z" stroke="url(#paint0_radial)" />
        <path id="newBlob2" d="M329.513 279.795C436.007 377.817 616.183 489.453 589.3 542.075C562.417 594.696 357.777 579.604 204.743 439.154C51.7086 298.704 14.8111 52.0941 35.1135 33.4613C55.4158 14.8285 219.661 178.683 329.513 279.795Z" stroke="url(#paint1_radial)" />
        <path id="newBlob" d="M345.686 210.898C266.403 155.201 137.026 96.9392 150.245 59.6563C163.464 22.3734 300.596 14.4156 414.492 94.1825C528.387 173.949 574.534 334.369 562.697 348.518C550.86 362.667 427.469 268.352 345.686 210.898Z" stroke="url(#paint2_radial)" />
        <path id="newStar" d="M197.175 83.8574C201.628 26.8764 276.394 8.88253 306.285 57.5982L350.768 130.097C364.135 151.883 390.011 162.585 414.861 156.604L497.558 136.701C553.126 123.328 593.343 188.874 556.249 232.356L501.044 297.065C484.455 316.511 482.273 344.427 495.641 366.213L540.124 438.712C570.014 487.428 520.104 545.932 467.287 524.089L388.686 491.582C365.066 481.814 337.842 488.366 321.253 507.812L266.048 572.521C228.953 616.002 157.89 586.613 162.342 529.632L168.969 444.833C170.96 419.35 156.316 395.483 132.696 385.715L54.0945 353.209C1.27822 331.366 7.26908 254.699 62.8371 241.325L145.534 221.423C170.384 215.442 188.558 194.139 190.549 168.657L197.175 83.8574Z" stroke="url(#paint3_radial)" />
      </g>

      <path id="electronLarge" d="M5 0C5 2.76142 2.76142 5 0 5C-2.76142 5 -5 2.76142 -5 0C-5 -2.76142 -2.76142 -5 0 -5C2.76142 -5 5 -2.76142 5 0Z" fill="#13adc7">
        <animateMotion dur="540s" repeatCount="indefinite" rotate="auto" begin=".3">
          <mpath xlinkHref="#ellipse1" />
        </animateMotion>
      </path>

      <path id="electronLarge" d="M5 0C5 2.76142 2.76142 5 0 5C-2.76142 5 -5 2.76142 -5 0C-5 -2.76142 -2.76142 -5 0 -5C2.76142 -5 5 -2.76142 5 0Z" fill="#13adc7">
        <animateMotion dur="660s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#newStar" />
        </animateMotion>
      </path>

      <path id="electronMedium" d="M2.5 0C2.5 1.38071 1.38071 2.5 0 2.5C-1.38071 2.5 -2.5 1.38071 -2.5 0C-2.5 -1.38071 -1.38071 -2.5 0 -2.5C1.38071 -2.5 2.5 -1.38071 2.5 0Z" fill="#13adc7">
        <animateMotion dur="800s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#newBlob" />
        </animateMotion>
      </path>

      <path id="electronMedium" d="M2.5 0C2.5 1.38071 1.38071 2.5 0 2.5C-1.38071 2.5 -2.5 1.38071 -2.5 0C-2.5 -1.38071 -1.38071 -2.5 0 -2.5C1.38071 -2.5 2.5 -1.38071 2.5 0Z" fill="#F46737">
        <animateMotion dur="600s" repeatCount="indefinite" rotate="auto" begin=".1">
          <mpath xlinkHref="#newBlob2" />
        </animateMotion>
      </path>

      <path id="electronLarge" d="M5 0C5 2.76142 2.76142 5 0 5C-2.76142 5 -5 2.76142 -5 0C-5 -2.76142 -2.76142 -5 0 -5C2.76142 -5 5 -2.76142 5 0Z" fill="#f46737">
        <animateMotion dur="480s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#ellipse2" />
        </animateMotion>
      </path>

      <path id="electronLarge" d="M5 0C5 2.76142 2.76142 5 0 5C-2.76142 5 -5 2.76142 -5 0C-5 -2.76142 -2.76142 -5 0 -5C2.76142 -5 5 -2.76142 5 0Z" fill="#945dd6">
        <animateMotion dur="300s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#newBlob3" />
        </animateMotion>
      </path>

      <path id="electronLarge" d="M5 0C5 2.76142 2.76142 5 0 5C-2.76142 5 -5 2.76142 -5 0C-5 -2.76142 -2.76142 -5 0 -5C2.76142 -5 5 -2.76142 5 0Z" fill="#13adc7">
        <animateMotion dur="490s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#crazyStar" />
        </animateMotion>
      </path>

      <path id="electronMedium" d="M2.5 0C2.5 1.38071 1.38071 2.5 0 2.5C-1.38071 2.5 -2.5 1.38071 -2.5 0C-2.5 -1.38071 -1.38071 -2.5 0 -2.5C1.38071 -2.5 2.5 -1.38071 2.5 0Z" fill="#F46737">
        <animateMotion dur="356s" repeatCount="indefinite" rotate="auto" begin=".1">
          <mpath xlinkHref="#crazyStar" />
        </animateMotion>
      </path>

      <path id="electronMedium" d="M2.5 0C2.5 1.38071 1.38071 2.5 0 2.5C-1.38071 2.5 -2.5 1.38071 -2.5 0C-2.5 -1.38071 -1.38071 -2.5 0 -2.5C1.38071 -2.5 2.5 -1.38071 2.5 0Z" fill="#945dd6">
        <animateMotion dur="180s" repeatCount="indefinite" rotate="auto" begin=".1">
          <mpath xlinkHref="#basicStar" />
        </animateMotion>
      </path>

      <path id="electronSmall" d="M1.00012 0C1.00012 0.552285 0.552407 1 0.00012207 1C-0.552163 1 -0.999878 0.552285 -0.999878 0C-0.999878 -0.552285 -0.552163 -1 0.00012207 -1C0.552407 -1 1.00012 -0.552285 1.00012 0Z" fill="#945dd6">
        <animateMotion dur="500s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#ellipse1" />
        </animateMotion>
      </path>

      <path id="tail2" d="M-1.33246e-07 0H-35.3553" stroke="url(#paint4_linear)">
        <animateMotion dur="500s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#ellipse1" />
        </animateMotion>
      </path>

      <path id="electronSmall" d="M1.00012 0C1.00012 0.552285 0.552407 1 0.00012207 1C-0.552163 1 -0.999878 0.552285 -0.999878 0C-0.999878 -0.552285 -0.552163 -1 0.00012207 -1C0.552407 -1 1.00012 -0.552285 1.00012 0Z" fill="#945dd6">
        <animateMotion dur="2000s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#basicStar" />
        </animateMotion>
      </path>

      <path id="tail2" d="M-1.33246e-07 0H-35.3553" stroke="url(#paint4_linear)">
        <animateMotion dur="2000s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#basicStar" />
        </animateMotion>
      </path>

      <path id="electronSmall" d="M1.00012 0C1.00012 0.552285 0.552407 1 0.00012207 1C-0.552163 1 -0.999878 0.552285 -0.999878 0C-0.999878 -0.552285 -0.552163 -1 0.00012207 -1C0.552407 -1 1.00012 -0.552285 1.00012 0Z" fill="#945dd6">
        <animateMotion dur="75s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#ellipse2" />
        </animateMotion>
      </path>

      <path id="tail2" d="M-1.33246e-07 0H-35.3553" stroke="url(#paint4_linear)">
        <animateMotion dur="75s" repeatCount="indefinite" rotate="auto">
          <mpath xlinkHref="#ellipse2" />
        </animateMotion>
      </path>

      <defs>
        <radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(300.984 270.268) rotate(125.638) scale(333.436)">
          <stop stopColor="#945DD6" />
          <stop offset="1" stopColor="#945DD6" stopOpacity="0" />
        </radialGradient>
        <radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(301 308) rotate(90) scale(290)">
          <stop stopColor="#945DD6" />
          <stop offset="1" stopColor="#945DD6" stopOpacity="0" />
        </radialGradient>
        <radialGradient id="paint2_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(301.355 300.355) rotate(135) scale(376.888 50)">
          <stop stopColor="#945DD6" />
          <stop offset="1" stopColor="#945DD6" stopOpacity="0" />
        </radialGradient>
        <radialGradient id="paint3_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(301.355 300.355) rotate(45) scale(376.888 50)">
          <stop stopColor="#945DD6" />
          <stop offset="1" stopColor="#945DD6" stopOpacity="0" />
        </radialGradient>

        <linearGradient id="paint4_linear" x1="0.846512" y1="-0.322612" x2="-33.5265" y2="-0.322041" gradientUnits="userSpaceOnUse">
          <stop stopColor="#945DD6" />
          <stop offset="1" stopColor="#945DD6" stopOpacity=".2" />
        </linearGradient>
      </defs>
    </svg>

Note: SVG can be optimized with tools like “SVGOMG” to minimize file size. The code above is 10kb.