DEV Community

Cover image for Create SVG 📽️ Spritesheet animations with 1 Template Literal String 🎬
Danny Engelman
Danny Engelman

Posted on • Edited on

Create SVG 📽️ Spritesheet animations with 1 Template Literal String 🎬

Disclaimer:

The Online SpriteMeister Generator: https://Sprite-Meister.github.io
is a Working Model v.042 - not intended for Production use. (but I use it for production, so can you)

Only an idiot creates yet another animation tool

There comes a point in time when you have to kill your darlings.
Drop development and toss the result in the bin, because you realize you must be the only idiot on this globe doing what you are doing.

I can't toss this one in the bin, spent many moons on it, it is too much fun, and the current version satisfies my needs.

Can other developers use this? I don't know. Let me know!

I donate all my code to the Public Domain.
Tagged with the Unlicense, so feel free to do whatever you want with it.

About Spritesheet Animations

It all started in 1872 when photographer Eadweard Muybridge took a sequence of images. And used a "projector" to quickly show each frame

The SpriteMeiser <sprite-animation> Web Component displays that whole JPG of 15 frames in the Browser. frame by frame

<script src="//sprite-meister.github.io/elements.js"></script>

<sprite-animation 
    steps="15"
    cell="183x122"
    duration="1s"
    src="//sprite-meister.github.io/spritesheets/muybridge_horse.jpg">
</sprite-animation>
Enter fullscreen mode Exit fullscreen mode

Creating a Sprite Sheet Animation:

But why stop there?

So everything required to animate a Hamburger icon to an Arrow is:

<script src="//sprite-meister.github.io/element.js"></script>

<sprite-meister duration="4s">
    ${ setv1( 40-ease({distance:25}) , "top and bottom X position" ) , 
       setv2(    ease({distance:20}) , "top and bottom line to Y=50" )
    }
    <g stroke="black" stroke-width="8" stroke-linecap="round" 
       transform="${rotate(180-ease({distance:180}))}">
        <path d="M${v1} 30L85 ${50 - v2}"></path>
        <path d="M15 50L85 50"></path>
        <path d="M${v1} 70L85 ${50 + v2}"></path>
    </g>
</sprite-meister>
Enter fullscreen mode Exit fullscreen mode

<sprite-meister> parses the String Literal to 24 (default) SVG frames:

Then PacMan is just 2 rotating semi-circles:

..and a squinting eye!

<script src="//sprite-meister.github.io/element.js"></script>

<sprite-meister duration="1s">
  ${ setv1( pulse({mid:45}) ,"rotation" ),
     setv2( ease({distance:1}) ,"squint eye")
  }
  <g fill="yellow">
    <g transform="rotate(${ -v1 } 50 50)">
      <path d="m90 50a1 1 0 0 0 -80 0"></path>
      <ellipse cx="60" cy="30" rx="${5 + v2}" ry="${5 - v2}" fill="black"></ellipse>
    </g>
    <path transform="rotate(${v1} 50 50)" d="m10 50a1 1 0 0 0 80 0"></path>
  </g>
</sprite-meister>
Enter fullscreen mode Exit fullscreen mode

in true OOP fashion, 1 ghost is a <template>:

<template spritemeister id="ghost" duration=".5s" steps="24" ghostcolor="hotpink">
  ${setv1(ease({distance:1}),"squeeze eyes")} 
  ${setv2(ease({distance:1}),"bounce eyes")} 
  ${setv3(pulse({mid:2}),"bounce ghost")} 
  ${setv4(pulse({start:0,mid:2}),"wiggle skirt")} 
  <g transform="skewY(${v3})">
    <path fill="${attr('ghostcolor','red')}"
          d="M82 94 c7-13 4-44 1-65s-40-55-63-1 c-7 22-7 53-3 66
             l${v4}-11 l7 11l8-13l8 13l8-12l8 12l7-12z"></path>
    <g id="eye${framenr}" transform="translate(0 ${v2})">
      <ellipse fill="white" cx="${58 + v1}" cy="${30 + v1}" rx="${5 + v1}" ry="${5 - v1}"></ellipse>
      <ellipse fill="black" cx="${60 + v1}" cy="${30 + v1}" rx="${1 + v1}" ry="${2 - v1}"></ellipse>
    </g>
    <use x="0" y="36" href="#eye${framenr}" transform="rotate(180 50 50)"></use>
    <text x="25" y="75">${attr("id")} </text>
  </g>
</template>
Enter fullscreen mode Exit fullscreen mode

Then 4 ghosts are created with:

<sprite-meister id="Blinky" template="ghost" ghostcolor="red"></sprite-meister>
<sprite-meister id="Pinky"  template="ghost" ghostcolor="hotpink"></sprite-meister>
<sprite-meister id="Inky"   template="ghost" ghostcolor="cyan"></sprite-meister>
<sprite-meister id="Clyde"  template="ghost" ghostcolor="orange"></sprite-meister>
Enter fullscreen mode Exit fullscreen mode

It works for me

The Online SpriteMeister Generator: https://Sprite-Meister.github.io

helped me create the spite-sheet animations I needed.

I hereby donate all my (Working Model) code to the Public Domain.

https://github.com/sprite-meister/sprite-meister.github.io


How it is done

<sprite-meister id="bounce" duration="1s" steps="24">
    <ellipse
    cx="50"
    cy="${70 - ease({distance:36})}"
    rx="${ framenr > 11 ? minmax({value:30,min:41 - ease({distance:10})}) : 30}"
    ry="${minmax({value:30,min:30 - ease({distance:30})})}"
    fill="none"
    stroke="red"
    stroke-width="5"
    ></ellipse>
    <text y="12">n:${framenr}</text>
</sprite-meister>
Enter fullscreen mode Exit fullscreen mode
  • The <sprite-meister> Web Component reads its content as a String
  • The String is passed to a parseStringLiteral Function
  • together with a {} data object containing variables AND functions (see 'ease' in above code)
  • every function generates ONE value for every frame-step
  • with all data the Web Component creates one SVG (24 framesteps wide)

Known issues

  • The Repo is a mess, all code should be refactored
  • Because 1 SVG is created for every frame-step, a Absolute reference will always point to frame 1
  • Same goes for % Percentages in the X plane
  • The SVG is 1 frame high, so Y plane percentages are fine
  • ...

Minimal documentation in documentation.html

I told you, it is a Working Model v.042

The Online SpriteMeister Generator: https://Sprite-Meister.github.io

#webcomponents

Everything about Web Components!

Top comments (1)

Collapse
 
yw662 profile image
yw662

Seems not very useful for simple animation, since there are already css transitions.
But a good alternative for morphing.