CSS sprite sheet animation

HTML

<img src="http://s.cdpn.io/79/sprite-steps.png" />
<div class="hi"></div>
<div class="hiHover"></div>

CSS

.hi {
    width: 50px;
    height: 72px;
    background-image: url("http://s.cdpn.io/79/sprite-steps.png");

    -webkit-animation: play .8s steps(10) infinite;
       -moz-animation: play .8s steps(10) infinite;
        -ms-animation: play .8s steps(10) infinite;
         -o-animation: play .8s steps(10) infinite;
            animation: play .8s steps(10) infinite;
}

.hiHover {
    width: 50px;
    height: 72px;
    background-image: url("http://s.cdpn.io/79/sprite-steps.png");
}
.hiHover:hover {
  
    -webkit-animation: play .8s steps(10) infinite;
       -moz-animation: play .8s steps(10) infinite;
        -ms-animation: play .8s steps(10) infinite;
         -o-animation: play .8s steps(10) infinite;
            animation: play .8s steps(10) infinite;
}

@-webkit-keyframes play {
   from { background-position:    0px; }
     to { background-position: -500px; }
}

@-moz-keyframes play {
   from { background-position:    0px; }
     to { background-position: -500px; }
}

@-ms-keyframes play {
   from { background-position:    0px; }
     to { background-position: -500px; }
}

@-o-keyframes play {
   from { background-position:    0px; }
     to { background-position: -500px; }
}

@keyframes play {
   from { background-position:    0px; }
     to { background-position: -500px; }
}

JavaScript

// Syncronzing CSS animations using https://github.com/bealearts/css-animation-sync

// Sprite Sheet animation with CSS3 using the steps() feature.
// To change the speed, just edit the ".8s" animation time.

// Post: http://simurai.com/blog/2012/12/03/step-animation/

// Inspired by Lea's typing animation: http://t.co/9RPMmV7

const defaultOptions = {
    graceful: true
};

function sync(animationName, options = {}) {
    const opts = {
        ...defaultOptions,
        ...options
    };

    const elements = new Set();
    let eventTime;
    let lastInterationTS = now();
    let interationDuration = 0;

    function animationStart(event) {
        if (event.animationName === animationName) {
            const el = event.target;

            if (opts.graceful && !elements.has(el) && interationDuration !== 0) {
                gracefulStart(el, interationDuration, lastInterationTS);
            }

            elements.add(el);
        }
    }

    function animationIteration(event) {
        if (event.animationName === animationName) {
            elements.add(event.target);

            requestAnimationFrame(frameTime => {
                if (frameTime !== eventTime) {
                    interationDuration = now() - lastInterationTS;
                    lastInterationTS = now();
                    restart(elements);
                }

                eventTime = frameTime;
            });
        }
    }


    window.addEventListener('animationstart', animationStart, true);
    window.addEventListener('animationiteration', animationIteration, true);


    return {
        free() {
            window.removeEventListener('animationstart', animationStart);
            window.removeEventListener('animationiteration', animationIteration);

            this.start();
            elements.clear();
        },

        start() {
            elements.forEach(el => {
                if (validate(elements, el)) {
                    el.style.removeProperty('animation');
 ...