Time-Based Animation (canvas example)

http://viget.com/inspire/time-based-animation

by greypants

HTML

<script src="http://danieltello.com/demos/time-based-animation/javascripts/requestAnimationFrame.js"></script>
<div id="canvas-demo">
    <div class="buttons">
        <label for="speed">Speed</label>
        <input name="speed" id="speed-input" type="number" value="200"> px/sec</input>
        <button onclick="APP.play();">Play</button>
        <button onclick="APP.pause();">Pause</button>
        <span class="framerate"><span id="framerate">0</span> fps</span>
    </div>
</div>

CSS

body, html {
    font-family: sans-serif;
    font-size: 14px;
    margin: 0;
    padding: 0;
}

#canvas-demo {
    max-width: 580px;
    overflow: hidden;
    position: relative;
    width: 100%;
}

canvas {
    background: #9adaea url(http://viget.com/uploads/file/time-based-animation/images/ground.png) repeat-x 0 100%;
}


#speed-input {
    width: 60px;
}

.buttons {
    -webkit-font-smoothing: antialiased;
    background: #201400;
    background: rgba(0,0,0,0.8);
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    -ms-box-sizing: border-box;
    box-sizing: border-box;
    color: #fff;
    font-weight: bold;
    height: 50px;
    line-height: 50px;
    padding: 0 10px;
    position: absolute;
    top: 288px;
    width: 100%;
    z-index: 1;
}

.framerate {
    float: right;
}

JavaScript

// Requires requestAnimationFrame polyfill
// https://gist.github.com/1579671

window.APP = window.APP || {};

APP.init = function() {
    APP.setup.createCanvas();
    APP.setup.createObjects();
    APP.setup.initSpeedInput();
    APP.setup.addListeners();
    APP.play();
};

APP.pause = function() {
    window.cancelAnimationFrame(APP.core.animationFrame);
    APP.core.isRunning = false;
};

APP.play = function() {
    if(!APP.core.isRunning) {
        APP.core.then = Date.now();
        APP.core.frame();
        APP.core.isRunning = true;
    }
};

APP.core = {

    frame: function() {
        APP.core.setDelta();
        APP.core.update();
        APP.core.render();
        APP.core.animationFrame = window.requestAnimationFrame(APP.core.frame);
    },

    setDelta: function() {
        APP.core.now = Date.now();
        APP.core.delta = (APP.core.now - APP.core.then) / 1000; // seconds since last frame
        APP.core.then = APP.core.now;
    },

    update: function() {
        APP.workers.moveObjects();
    },

    render: function() {
        APP.workers.clearCanvas();
        APP.workers.renderGraphics();
        APP.workers.renderFrameRate();
    }
};

APP.setup = {

    addListeners: function() {
        // Makes demo responsive for small screens
        window.addEventListener('resize', APP.workers.moveCannon);
    },

    createCanvas: function() {
        APP.canvas = document.createElement('canvas');
        APP.canvas.width = 580;
        APP.canvas.height = 338;
        APP.canvas.ctx = APP.canvas.getContext('2d');
        document.getElementById('canvas-demo').appendChild(APP.canvas);
    },

    createObjects: function() {
        // Create Bullet
        APP.bullet = {
            img: document.createElement('img'),
            x: 460,
            y: 114,
            height: 56,
            width: 64,
            startX: 460,
            speed: 100 // pixels per second
        };
        APP.bullet.img.src =...