Animated JPEG

Uses JPEG and Javascript instead of an animated GIF to create something better. See http://stackoverflow.com/a/10139720/124119 for more info.

by Camilo

HTML

<i>Ok imgur hates me. Links edited to use eho.st</i>

<div id="sprite"></div>

<p>This animated image uses JPEG compression to achieve 476 KB (+ ~2 KB JSON).</p>
<p> A gif of the same size (compressed with a good tool) looks completely horrible: <a href="http://i.eho.st/pgfxn0vy.gif">478KB gif</a>.</p>
<p>A better-looking gif weights almost three times more: <a href="http://i.eho.st/pgs3rllb.gif">1.26MB gif</a>.></p>
<p>Here's a (not much different) lossless version: <a href="http://www.mediafire.com/?czh31l58bp7uuc1">3.87 MB avi</a></p>
    
<center>
    <button onclick="animate()">Animate</button>
    <button onclick="stop()">Stop</button>
</center>

<p>Credit for the image: <a href="http://v2d7c.sheepserver.net/cgi/dead.cgi?id=10479">Electric Sheep</a>.</p>
    
<p>Tested in Chrome 18, IE 8, Firefox 11.</p>

CSS

#sprite {
    background: url('http://i.eho.st/pjw35bzm.jpg');
    position: relative;
    height: 160px;
    width: 160px;
    left: 50%;
    margin-left: -80px;
    margin-top: 1em;
    color: white;
    font-family: sans-serif;
    text-shadow: 0 1px 1px black;
}
p { font-family: sans-serif; margin: 1em }

JavaScript

function animateSprite(div, data, pos) {
    if(!pos) var pos = 0; // Default position.
    var stopAttribute = div.getAttribute('stop');
    if(stopAttribute == 'true' && pos != 0) return;
    div.setAttribute('stop', 'false')
    var frames = data.frames; // Frames array.
    var frame = frames[pos]; // Current frame.
    var x = frame.x; // X offset of the frame.
    var y = frame.y; // Y offset of the frame.
    var ms = frame.ms; // Frame duration (ms).
    var offsets = '-' + x + 'px -' + y + 'px';
    div.style.backgroundPosition = offsets;
    div.innerText = 'Frame ' + pos;
    var newPos = (frames[pos + 1] ? pos + 1 : 0);
    // Curry in this case is not a tasty food.
    var curry = function() {
        animateSprite(div, data, newPos)
    };
    setTimeout(curry, ms);
    // I've aligned all the comments' periods.
    // But, I wouldn't write that in a commit.
}

function animate() {
    var div = document.getElementById('sprite');
    animateSprite(div, json);
}

function stop() {
    var div = document.getElementById('sprite');
    div.setAttribute('stop', 'true')
}

var json = {
    "framesize": {
        "w":160,
        "h":160,
    },
    "frames": [
        {"x":0,"y":0,"ms":66},
        {"x":160,"y":0,"ms":66},
        {"x":320,"y":0,"ms":66},
        {"x":480,"y":0,"ms":66},
        {"x":640,"y":0,"ms":66},
        {"x":800,"y":0,"ms":66},
        {"x":960,"y":0,"ms":66},
        {"x":1120,"y":0,"ms":66},
        {"x":1280,"y":0,"ms":66},
        {"x":1440,"y":0,"ms":66},
        {"x":1600,"y":0,"ms":66},
        {"x":1760,"y":0,"ms":66},
        {"x":0,"y":160,"ms":66},
        {"x":160,"y":160,"ms":66},
        {"x":320,"y":160,"ms":66},
        {"x":480,"y":160,"ms":66},
        {"x":640,"y":160,"ms":66},
        {"x":800,"y":160,"ms":66},
        {"x":960,"y":160,"ms":66},
        {"x":1120,"y":160,"ms":66},
        {"x":1280,"y":160,"ms":66},
        {"x":1440,"y":160,"ms":66},
        {"x":1600,"y":160,"ms":66},
       ...