Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Designing For TV: Principles, Patterns And Practical Guidance (Part 2)

      September 5, 2025

      Neo4j introduces new graph architecture that allows operational and analytics workloads to be run together

      September 5, 2025

      Beyond the benchmarks: Understanding the coding personalities of different LLMs

      September 5, 2025

      Top 10 Use Cases of Vibe Coding in Large-Scale Node.js Applications

      September 3, 2025

      Building smarter interactions with MCP elicitation: From clunky tool calls to seamless user experiences

      September 4, 2025

      From Zero to MCP: Simplifying AI Integrations with xmcp

      September 4, 2025

      Distribution Release: Linux Mint 22.2

      September 4, 2025

      Coded Smorgasbord: Basically, a Smorgasbord

      September 4, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Drupal 11’s AI Features: What They Actually Mean for Your Team

      September 5, 2025
      Recent

      Drupal 11’s AI Features: What They Actually Mean for Your Team

      September 5, 2025

      Why Data Governance Matters More Than Ever in 2025?

      September 5, 2025

      Perficient Included in the IDC Market Glance for Digital Business Professional Services, 3Q25

      September 5, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      How DevOps Teams Are Redefining Reliability with NixOS and OSTree-Powered Linux

      September 5, 2025
      Recent

      How DevOps Teams Are Redefining Reliability with NixOS and OSTree-Powered Linux

      September 5, 2025

      Distribution Release: Linux Mint 22.2

      September 4, 2025

      ‘Cronos: The New Dawn’ was by far my favorite experience at Gamescom 2025 — Bloober might have cooked an Xbox / PC horror masterpiece

      September 4, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Tech & Work»Smashing Animations Part 4: Optimising SVGs

    Smashing Animations Part 4: Optimising SVGs

    June 4, 2025

    SVG animations take me back to the Hanna-Barbera cartoons I watched as a kid. Shows like Wacky Races, The Perils of Penelope Pitstop, and, of course, Yogi Bear. They inspired me to lovingly recreate some classic Toon Titles using CSS, SVG, and SMIL animations.

    But getting animations to load quickly and work smoothly needs more than nostalgia. It takes clean design, lean code, and a process that makes complex SVGs easier to animate. Here’s how I do it.

    Start Clean And Design With Optimisation In Mind

    Keeping things simple is key to making SVGs that are optimised and ready to animate. Tools like Adobe Illustrator convert bitmap images to vectors, but the output often contains too many extraneous groups, layers, and masks. Instead, I start cleaning in Sketch, work from a reference image, and use the Pen tool to create paths.

    Tip: Affinity Designer (UK) and Sketch (Netherlands) are alternatives to Adobe Illustrator and Figma. Both are independent and based in Europe. Sketch has been my default design app since Adobe killed Fireworks.

    Beginning With Outlines

    For these Toon Titles illustrations, I first use the Pen tool to draw black outlines with as few anchor points as possible. The more points a shape has, the bigger a file becomes, so simplifying paths and reducing the number of points makes an SVG much smaller, often with no discernible visual difference.

    Bearing in mind that parts of this Yogi illustration will ultimately be animated, I keep outlines for this Bewitched Bear’s body, head, collar, and tie separate so that I can move them independently. The head might nod, the tie could flap, and, like in those classic cartoons, Yogi’s collar will hide the joins between them.

    Drawing Simple Background Shapes

    With the outlines in place, I use the Pen tool again to draw new shapes, which fill the areas with colour. These colours sit behind the outlines, so they don’t need to match them exactly. The fewer anchor points, the smaller the file size.

    Sadly, neither Affinity Designer nor Sketch has tools that can simplify paths, but if you have it, using Adobe Illustrator can shave a few extra kilobytes off these background shapes.

    Optimising The Code

    It’s not just metadata that makes SVG bulkier. The way you export from your design app also affects file size.

    Exporting just those simple background shapes from Adobe Illustrator includes unnecessary groups, masks, and bloated path data by default. Sketch’s code is barely any better, and there’s plenty of room for improvement, even in its SVGO Compressor code. I rely on Jake Archibald’s SVGOMG, which uses SVGO v3 and consistently delivers the best optimised SVGs.

    Layering SVG Elements

    My process for preparing SVGs for animation goes well beyond drawing vectors and optimising paths — it also includes how I structure the code itself. When every visual element is crammed into a single SVG file, even optimised code can be a nightmare to navigate. Locating a specific path or group often feels like searching for a needle in a haystack.

    That’s why I develop my SVGs in layers, exporting and optimising one set of elements at a time — always in the order they’ll appear in the final file. This lets me build the master SVG gradually by pasting it in each cleaned-up section. For example, I start with backgrounds like this gradient and title graphic.

    Instead of facing a wall of SVG code, I can now easily identify the background gradient’s path and its associated linearGradient, and see the group containing the title graphic. I take this opportunity to add a comment to the code, which will make editing and adding animations to it easier in the future:

    <svg ...>
      <defs>
        <!-- ... -->
      </defs>
      <path fill="url(#grad)" d="…"/>
      <!-- TITLE GRAPHIC -->
      <g>
        <path … />
        <!-- ... --> 
      </g>
    </svg>
    

    Next, I add the blurred trail from Yogi’s airborne broom. This includes defining a Gaussian Blur filter and placing its path between the background and title layers:

    <svg ...>
      <defs>
        <linearGradient id="grad" …>…</linearGradient>
        <filter id="trail" …>…</filter>
      </defs>
      <!-- GRADIENT -->
      <!-- TRAIL -->
      <path filter="url(#trail)" …/>
      <!-- TITLE GRAPHIC -->
    </svg>
    

    Then come the magical stars, added in the same sequential fashion:

    <svg ...>
      <!-- GRADIENT -->
      <!-- TRAIL -->
      <!-- STARS -->
      <!-- TITLE GRAPHIC -->
    </svg>
    

    To keep everything organised and animation-ready, I create an empty group that will hold all the parts of Yogi:

    <g id="yogi">...</g>
    

    Then I build Yogi from the ground up — starting with background props, like his broom:

    <g id="broom">...</g>
    

    Followed by grouped elements for his body, head, collar, and tie:

    <g id="yogi">
      <g id="broom">…</g>
      <g id="body">…</g>
      <g id="head">…</g>
      <g id="collar">…</g>
      <g id="tie">…</g>
    </g>
    

    Since I export each layer from the same-sized artboard, I don’t need to worry about alignment or positioning issues later on — they’ll all slot into place automatically. I keep my code clean, readable, and ordered logically by layering elements this way. It also makes animating smoother, as each component is easier to identify.

    Reusing Elements With <use>

    When duplicate shapes get reused repeatedly, SVG files can get bulky fast. My recreation of the “Bewitched Bear” title card contains 80 stars in three sizes. Combining all those shapes into one optimised path would bring the file size down to 3KB. But I want to animate individual stars, which would almost double that to 5KB:

    <g id="stars">
     <path class="star-small" fill="#eae3da" d="..."/>
     <path class="star-medium" fill="#eae3da" d="..."/>
     <path class="star-large" fill="#eae3da" d="..."/>
     <!-- ... -->
    </g>
    

    Moving the stars’ fill attribute values to their parent group reduces the overall weight a little:

    <g id="stars" fill="#eae3da">
     <path class="star-small" d="…"/>
     <path class="star-medium" d="…"/>
     <path class="star-large" d="…"/>
     <!-- ... -->
    </g>
    

    But a more efficient and manageable option is to define each star size as a reusable template:

    <defs>
      <path id="star-large" fill="#eae3da" fill-rule="evenodd" d="…"/>
      <path id="star-medium" fill="#eae3da" fill-rule="evenodd" d="…"/>
      <path id="star-small" fill="#eae3da" fill-rule="evenodd" d="…"/>
    </defs>
    

    With this setup, changing a star’s design only means updating its template once, and every instance updates automatically. Then, I reference each one using <use> and position them with x and y attributes:

    <g id="stars">
      <!-- Large stars -->
      <use href="#star-large" x="1575" y="495"/>
      <!-- ... -->
      <!-- Medium stars -->
      <use href="#star-medium" x="1453" y="696"/>
      <!-- ... -->
      <!-- Small stars -->
      <use href="#star-small" x="1287" y="741"/>
      <!-- ... -->
    </g>
    

    This approach makes the SVG easier to manage, lighter to load, and faster to iterate on, especially when working with dozens of repeating elements. Best of all, it keeps the markup clean without compromising on flexibility or performance.

    Adding Animations

    The stars trailing behind Yogi’s stolen broom bring so much personality to the animation. I wanted them to sparkle in a seemingly random pattern against the dark blue background, so I started by defining a keyframe animation that cycles through different opacity levels:

    @keyframes sparkle {
      0%, 100% { opacity: .1; }
      50% { opacity: 1; }
    }
    

    Next, I applied this looping animation to every use element inside my stars group:

    #stars use {
      animation: sparkle 10s ease-in-out infinite;
    }
    

    The secret to creating a convincing twinkle lies in variation. I staggered animation delays and durations across the stars using nth-child selectors, starting with the quickest and most frequent sparkle effects:

    /* Fast, frequent */
    #stars use:nth-child(n + 1):nth-child(-n + 10) {
      animation-delay: .1s;
      animation-duration: 2s;
    }
    

    From there, I layered in additional timings to mix things up. Some stars sparkle slowly and dramatically, others more randomly, with a variety of rhythms and pauses:

    /* Medium */
    #stars use:nth-child(n + 11):nth-child(-n + 20) { ... }
    
    /* Slow, dramatic */
    #stars use:nth-child(n + 21):nth-child(-n + 30) { ... }
    
    /* Random */
    #stars use:nth-child(3n + 2) { ... }
    
    /* Alternating */
    #stars use:nth-child(4n + 1) { ... }
    
    /* Scattered */
    #stars use:nth-child(n + 31) { ... }
    

    By thoughtfully structuring the SVG and reusing elements, I can build complex-looking animations without bloated code, making even a simple effect like changing opacity sparkle.

    Then, for added realism, I make Yogi’s head wobble:

    @keyframes headWobble {
      0% { transform: rotate(-0.8deg) translateY(-0.5px); }
      100% { transform: rotate(0.9deg) translateY(0.3px); }
    }
    
    #head {
      animation: headWobble 0.8s cubic-bezier(0.5, 0.15, 0.5, 0.85) infinite alternate;
    }
    

    His tie waves:

    @keyframes tieWave {
      0%, 100% { transform: rotateZ(-4deg) rotateY(15deg) scaleX(0.96); }
      33% { transform: rotateZ(5deg) rotateY(-10deg) scaleX(1.05); }
      66% { transform: rotateZ(-2deg) rotateY(5deg) scaleX(0.98); }
    }
    
    #tie {
      transform-style: preserve-3d;
      animation: tieWave 10s cubic-bezier(0.68, -0.55, 0.27, 1.55) infinite;
    }
    

    His broom swings:

    @keyframes broomSwing {
      0%, 20% { transform: rotate(-5deg); }
      30% { transform: rotate(-4deg); }
      50%, 70% { transform: rotate(5deg); }
      80% { transform: rotate(4deg); }
      100% { transform: rotate(-5deg); }
    }
    
    #broom {
      animation: broomSwing 4s cubic-bezier(0.5, 0.05, 0.5, 0.95) infinite;
    }
    

    And, finally, Yogi himself gently rotates as he flies on his magical broom:

    @keyframes yogiWobble {
      0% { transform: rotate(-2.8deg) translateY(-0.8px) scale(0.998); }
      30% { transform: rotate(1.5deg) translateY(0.3px); }
      100% { transform: rotate(3.2deg) translateY(1.2px) scale(1.002); }
    }
    
    #yogi {
      animation: yogiWobble 3.5s cubic-bezier(.37, .14, .3, .86) infinite alternate;
    }
    

    All these subtle movements bring Yogi to life. By developing structured SVGs, I can create animations that feel full of character without writing a single line of JavaScript.

    Try this yourself:

    See the Pen Bewitched Bear CSS/SVG animation [forked] by Andy Clarke.

    Conclusion

    Whether you’re recreating a classic title card or animating icons for an interface, the principles are the same:

    1. Start clean,
    2. Optimise early, and
    3. Structure everything with animation in mind.

    SVGs offer incredible creative freedom, but only if kept lean and manageable. When you plan your process like a production cell — layer by layer, element by element — you’ll spend less time untangling code and more time bringing your work to life.

    Source: Read More 

    news
    Facebook Twitter Reddit Email Copy Link
    Previous ArticleThe AI Fix #53: An AI uses blackmail to save itself, and threats make AIs work better
    Next Article projektgopher/whisky

    Related Posts

    Tech & Work

    Designing For TV: Principles, Patterns And Practical Guidance (Part 2)

    September 5, 2025
    Tech & Work

    Neo4j introduces new graph architecture that allows operational and analytics workloads to be run together

    September 5, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    j-Importer – Total.js

    Development

    Two Mirai Botnets, Lzrd and Resgod Spotted Exploiting Wazuh Flaw

    Security

    CVE-2025-4668 – Apache HTTP Server Deserialization Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-53024 – Oracle Virtualization VirtualBox Core High Privilege Takeover Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    Highlights

    CVE-2025-52724 – BoldThemes Amwerk Object Injection Vulnerability

    June 27, 2025

    CVE ID : CVE-2025-52724

    Published : June 27, 2025, 12:15 p.m. | 2 hours, 14 minutes ago

    Description : Deserialization of Untrusted Data vulnerability in BoldThemes Amwerk allows Object Injection. This issue affects Amwerk: from n/a through 1.2.0.

    Severity: 9.8 | CRITICAL

    Visit the link for more details, such as CVSS details, affected products, timeline, and more…

    CVE-2025-6070 – WordPress Restrict File Access Directory Traversal

    June 14, 2025

    CVE-2025-20307 – Cisco BroadWorks Application Delivery Platform Cross-Site Scripting (XSS) Vulnerability

    July 2, 2025

    GuardianGamer scales family-safe cloud gaming with AWS

    May 27, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.