Edit in JSFiddle


              
<head>
	<title>Hipster Dog — Shiny Demos</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width">
	<link rel="stylesheet" href="styles/screen.css">
	<link rel="stylesheet" href="/styles/panel.css">
</head>
<body>
	<div id="countryside">
		<input type="button" id="start" value="Start!" name="joyButton" style="display:none;">
		<input type="button" id="sound" value="Toggle Sound" name="sound">
		<div id="old_bicycle">
			<div id="bicycle_frame"></div>
			<div id="big_wheel"></div>
			<div id="small_wheel"></div>
		</div>
		<div id="doggie"></div>
		<audio loop id="music">
			<source src="http://media.shinydemos.com/hipster-dog/polka.mp3" type="audio/mpeg">
			<source src="http://media.shinydemos.com/hipster-dog/polka.ogg" type="audio/ogg">
		</audio>
		<audio id="effect">
			<source src="http://media.shinydemos.com/hipster-dog/effect.mp3" type="audio/mpeg">
			<source src="http://media.shinydemos.com/hipster-dog/effect.ogg" type="audio/ogg">
		</audio>
	</div>
	<!-- 
		Countryside near Amberley picture by Jim Mead http://www.flickr.com/photos/jimmead/4935440241/ 
		Toast Shoe picture by Mike Oliva http://www.flickr.com/photos/mikeyoliva/3968292186/
		Pixel Peeker Polka melody by Kevin McLeod http://incompetech.com/m/c/royalty-free/index.html?keywords=pixel
	-->
	<script src="/scripts/modernizr.js"></script>
	<script src="/scripts/panel.js"></script>
	<script src="scripts/options.js"></script>
	<script src="scripts/script.js"></script>
<script>
var $ = function(d) { return document.getElementById(d); },
    $$ = function(d) { return document.querySelectorAll(d); },
    prefixes = ['', '-o-', '-webkit-', '-moz-', '-ms-'],
    setStyles = function(dom, options, usePrefix) {
      var style = dom.style;
      for (var opt in options) {
        for (var i = 0, l = usePrefix ? prefixes.length : 1; i < l; ++i) {
          style.setProperty(prefixes[i] + opt, options[opt], '');
        }
      }
    },
    flushStyles = function(dom, properties, usePrefix) {
  	  properties.forEach(function (p) {
        for (var i = 0, l = usePrefix ? prefixes.length : 1; i < l; ++i) {
  		    getComputedStyle(dom).getPropertyValue(prefixes[i] + p);
  	    }
  	  });
    };    

//Cross browser requestAnimationFrame
(function() {
  this.Fx = {};

  var found = false,
      me = this;

  ['oRequestAnimationFrame',
   'webkitRequestAnimationFrame',
   'msRequestAnimationFrame',
   'mozRequestAnimationFrame',
   'requestAnimationFrame'].forEach(function(impl) {
    if (impl in this) {
      Fx.requestAnimationFrame = function(callback) {
        me[impl](function() {
          callback();
        });
      };
      found = true;
    }
  });
  
  if (!found) {
    Fx.requestAnimationFrame = function(callback) {
      setTimeout(function() {
        callback();
      }, 1000 / 60);
    };
  }
})();


//Extend dom elements with some
//functionality
function DOM(id) {
  this.element = $(id);
}

DOM.prototype = {
  setStyles: function(options, prefix) {
    setStyles(this.element, options, prefix);
  },
  flushStyles: function(options, prefix) {
    flushStyles(this.element, options, prefix);
  }
};

//Dog element
function Dog (id) {
  DOM.call(this, id);

  this.setStyles({
    'animation-name': '',
    'animation-duration': '3s',
    'animation-iteration-count': '1',
    'transform-origin': '40px 40px'
  }, true);
}

Dog.prototype = Object.create(DOM.prototype, {
  dixit: {
    value: ["Wicked!!!",
            "Wooo-hooo!",
            "Oh, my! This was unexpected...",
            "Yippeeeee!",
            "Who let the shoes out?",
            "Yeeeee-haw!!",
            "Blimey!",
            "What is this witchcraft?!?!",
            "Zoinks!",
            "Shiver-my-merkin!",
            "What a ride!",
            "Squally pocker dum!",
            "GAZOOBA!"]
  }
});

//Shoe element
function Shoe (id) {
  this.element = document.createElement('div');
}

Shoe.prototype = Object.create(DOM.prototype, {
  timer: {
    value: null,
    writable: true
  },
  shoeInit: {
    value: 920,
    writable: true
  },
  add: {
    value: function(countryside) {
      var shoeInit = this.shoeInit,
          element = this.element;

      element.setAttribute('id', 'shoe');
      element.classList.remove('hide');

      countryside.element.appendChild(this.element);
      countryside.imageInX = countryside.imageX;

      this.setStyles({
        'left': shoeInit + 'px'
      });
    }
  },
  remove: {
    value: function(countryside) {
      clearTimeout(this.timer);
      this.element.classList.add('hide');
      this.timer = setTimeout(this.add.bind(this, countryside), 1000);
    }
  }
});

//old bicycle.
function Bicycle (id) {
  DOM.call(this, id);
  this.smallWheel = $('small_wheel');
  this.bigWheel = $('big_wheel');
  this.setStyles({
    'animation-name': '',
    'animation-duration': '3s',
    'animation-iteration-count': '1',
    'transform-origin': '30px 312px'
  }, true);

  setStyles(this.smallWheel, {
    'animation-name': '',
    'animation-duration': '5s',
    'animation-iteration-count': 'infinite',
    'transform-origin': 'center center',
    'animation-timing-function': 'linear'
  }, true);

  setStyles(this.bigWheel, {
    'animation-name': '',
    'animation-duration': '3s',
    'animation-iteration-count': 'infinite',
    'transform-origin': 'center center',
    'animation-timing-function': 'linear'
  }, true);
}

Bicycle.prototype = Object.create(DOM.prototype);

//countryside element
function Countryside (id) {
  DOM.call(this, id);
}

Countryside.prototype = Object.create(DOM.prototype, {
  imageX: {
    value: 0,
    writable: true
  },
  imageY: {
    value: 0,
    writable: true
  },
  imageInX: {
    value: 0,
    writable: true
  },
  imageInY: {
    value: 0,
    writable: true
  },
  moveBackground: {
    value: function(x, y) {
      this.imageX  = (this.imageX + x); //image width
      // this.imageInX %= 3658; //image width
      this.imageY += y;
      this.element.style.backgroundPosition = this.imageX + 'px ' + this.imageY + 'px';
    }
  }
});

//Bubble object
function Bubble (text) {
  var me = this,
      id = 'bubble' + Bubble.id++;

  Bubble.pool.push(me);

  var element = document.createElement('div');
  element.setAttribute('id', id);
  element.classList.add('bubble');

  var box = document.createElement('div');
  box.setAttribute('id', id + 'box');
  box.classList.add('bubble1');
  box.innerHTML = text;

  var edge = document.createElement('div');
  edge.setAttribute('id', id + 'edge');
  edge.classList.add('bubble2');

  element.appendChild(box);
  element.appendChild(edge);

  me.element = element;

  me.setStyles({
    'top': '175px',
    'left': '144px'
  });
}

Bubble.id = 0;
Bubble.pool = [];
Bubble.update = function(scene) {
  this.pool.forEach(function(bubble, index) {
    var element = bubble.element,
        style = element.style,
        top = parseInt(style.top, 10),
        height = element.offsetHeight + 1,
        imageX = scene.countryside.imageX;

    if (top >= -height) {
      style.top = (top - 1) + 'px';
      style.left = ((Math.floor( (imageX - bubble.backBubIn) / 10 ) + 144) || -500) + 'px';
    } else {
      this.splice(index, 1);
    }
  }, this.pool);
};

Bubble.prototype = Object.create(DOM.prototype);


window.addEventListener('DOMContentLoaded', function() {
  //create dom elements
  var dog  = new Dog('doggie'),
      bike = new Bicycle('old_bicycle'),
      shoe = new Shoe('shoe'),
      countryside = new Countryside('countryside'),
      music = $('music'),
      effect = $('effect'),
      scene = { dog: dog, bike: bike, shoe: shoe, countryside: countryside },
      button = $('start'),
      toggleSound = $('sound'),
      riding = false,
      setRide = function(set) { riding = set; };

  //add up and down listeners
  button.addEventListener('click', function() {
    setRide(true);
    if (music.paused) {
      music.play();
    } else {
      music.pause();
    }
  }, false);
  
  button.click();
  toggleSound.addEventListener('click', function() {
    music[music.paused ? 'play' : 'pause']();
  }, false);

  //add shoe
  shoe.add(countryside);

  //init loop
  loop();

  //loop
  function loop() {
    if (!riding) {
      Fx.requestAnimationFrame(loop);
      return;
    }

    //move the wheels
    setStyles(bike.smallWheel, {
      'animation-name': 'wheel'
    }, true);
    setStyles(bike.bigWheel, {
      'animation-name': 'wheel'
    }, true);

    /* motion rate 5px left */
    countryside.moveBackground(-2, 0);

    var imageX   = countryside.imageX,
        imageInX = countryside.imageInX,
        shoeInit = shoe.shoeInit;
        
    //console.log(imageX, imageInX, shoeInit, (imageX - imageInX + shoeInit) + 'px');
    shoe.setStyles({
      'left': (imageX - imageInX + shoeInit) + 'px'
    });
    

    //colision with the shoe when the shoe's left == 400
    if(imageX - imageInX + shoeInit == 416){
      //play sound effect
      if (!music.paused) {
        effect.play();
      }
      //reset animations
      bike.setStyles({
        'animation-name': ''
      }, true);
      dog.setStyles({
        'animation-name': ''
      }, true);
      //flush styles
      bike.flushStyles(['animation-name'], true);
      dog.flushStyles( ['animation-name'], true);
      setTimeout(function() {
        //set new animations
        bike.setStyles({
          'animation-name': 'willy'
        }, true);
        dog.setStyles({
          'animation-name': 'swirl'
        }, true);
      }, 10);
      //create a new bubble
      var bubble = new Bubble( dog.dixit[Math.random() * dog.dixit.length >> 0] );
      countryside.element.appendChild(bubble.element);

      setTimeout(function() {
        bubble.element.style.visibility = 'visible';
        bubble.backBubIn = countryside.imageX;
        shoe.remove(countryside);
      }, 1000);
    }

    Bubble.update(scene);

    Fx.requestAnimationFrame(loop);
  }
}, false);
</script>







html, body {
  margin: 0;
  padding: 0;
  background-color: black;
}

#sound {
    position: absolute;
    right: 10px;
}

@-webkit-keyframes willy {0% {
    -webkit-transform: rotate(0deg);
  }
  10% {
    -webkit-transform: rotate(-10deg);
  }
  30% {
    -webkit-transform: rotate(-20deg);
  }
  80% {
    -webkit-transform: rotate(-21deg);
  }
  100% {
    -webkit-transform: rotate(0deg);
  }
}

@-webkit-keyframes swirl {0% {
    -webkit-transform: rotate(0deg);
  }
  50% {
    -webkit-transform: translate(0, -200px) rotate(-180deg);
  }
  100% {
    -webkit-transform: translate(0, 0px) rotate(-360deg);
  }
}

@-o-keyframes willy {0% {
    -o-transform: rotate(0deg);
  }
  10% {
    -o-transform: rotate(-10deg);
  }
  30% {
    -o-transform: rotate(-20deg);
  }
  80% {
    -o-transform: rotate(-21deg);
  }
  100% {
    -o-transform: rotate(0deg);
  }
}

@-o-keyframes swirl {0% {
    -o-transform: rotate(0deg);
  }
  50% {
    -o-transform: translate(0,-200px) rotate(-180deg);
  }
  100% {
    -o-transform: translate(0,0px) rotate(0deg);
  }
}

@-moz-keyframes willy {0% {
    -moz-transform: rotate(0deg);
  }
  10% {
    -moz-transform: rotate(-10deg);
  }
  30% {
    -moz-transform: rotate(-20deg);
  }
  80% {
    -moz-transform: rotate(-21deg);
  }
  100% {
    -moz-transform: rotate(0deg);
  }
}

@-moz-keyframes swirl {0% {
    -moz-transform: rotate(0deg);
  }
  50% {
    -moz-transform: translate(0,-200px) rotate(-180deg);
  }
  100% {
    -moz-transform: translate(0,0px) rotate(0deg);
  }
}

@keyframes willy {0% {
    transform: rotate(0deg);
  }
  10% {
    transform: rotate(-10deg);
  }
  30% {
    transform: rotate(-20deg);
  }
  80% {
    transform: rotate(-21deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

@keyframes swirl {0% {
    transform: rotate(0deg);
  }
  50% {
    transform: translate(0, -200px) rotate(-180deg);
  }
  100% {
    transform: translate(0, 0px) rotate(-360deg);
  }
}

@-webkit-keyframes wheel {
  0% {
    -webkit-transform: rotate(0);
  }
  100% {
    -webkit-transform: rotate(360deg);
  }
}

@-moz-keyframes wheel {
  0% {
    -moz-transform: rotate(0);
  }
  100% {
    -moz-transform: rotate(360deg);
  }
}

@-o-keyframes wheel {
  0% {
    -o-transform: rotate(0);
  }
  100% {
    -o-transform: rotate(360deg);
  }
}

@keyframes wheel {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

#countryside {
  width: 100%;
  /* width: 900px;*/
  height: 800px;
  padding: 10px 0 10px 0;
  background-image: url(../images/countryside.jpg);
  background-position: 0px 0px;
  position: relative;
  background-repeat: repeat-x;
  overflow: hidden;
}

#shoe {
  width: 395px;
  height: 150px;
  background-image: url(../images/shoe.png);	
  background-position: 0 0;
  position: absolute;
  /*top: 535px;*/
  top: 545px;
  background-repeat: no-repeat;
  opacity: 1;

  -webkit-transition: opacity 1000ms;
  -o-transition: opacity 1000ms;
  -moz-transition: opacity 1000ms;
  -ms-transition: opacity 1000ms;
  transition: opacity 1000ms;
}

#shoe.hide {
  opacity: 0;
}


#old_bicycle {
  width: 364px;
  height: 312px;
  position: absolute;
  /*top: 316px;*/
  top: 346px;
  left: 100px;
  background-repeat: no-repeat;
}

#big_wheel, #small_wheel, #bicycle_frame {
  position: absolute;
  background-position: 0 0;
  background-repeat: no-repeat;
}

#big_wheel {
  background-image: url(../images/big_wheel.png);
  width: 258px;
  height: 258px;
  top: 70px;
  left: 100px;
}

#small_wheel {
  background-image: url(../images/small_wheel.png);
  width: 99px;
  height: 99px;
  top: 210px;
  left: 0;
}

#bicycle_frame {
  background-image: url(../images/bicycle_frame.png);
  width: 210px;
  height: 261px;
  top: 5px;
  left: 42px;
}

#doggie {
  width: 80px;
  height: 80px;
  background-image: url(http://media.shinydemos.com/hipster-dog/doggie.png);
  background-position: 0 0;
  position: absolute;
  top: 313px;
  left: 234px;
  background-repeat: no-repeat;
}
.bubble {
  width: 94px;
  /*height: 64px;*/
  background-position: 0px 0px;
  position: absolute;
  background-repeat: no-repeat;
  visibility: hidden;
}
.bubble1 {
  width: 90px;
  padding: 4px;
  background-color: #fff;
  border: 1px solid #000;
  border-radius: 10px;
  background-position: 0 0;
  background-repeat: no-repeat;
}
.bubble2{
  width: 24px;
  height: 23px;
  margin: -1px 0 0 60px;
  background: url(../images/bubble_arrow.gif);
  background-repeat: no-repeat; 
}