1 juin 2014

Velocity.js and Meteor


Velocity.js is a new animation library in JS. It acts as a replacement of jQuery's animation library. Internally, it uses the CSS3 transformation and animation properties leveraging their hardware acceleration capabilities where possible and falling back on basic jQuery's animation when they are not available. Neat. Here is a small video of a simple animation developed by its creator:
Doing front end development with Meteor is so easy that I've recreated this demo and deployed it in less than one hour. Here is the result: http://velocity3ddemo.meteor.com/

Step-by-step recreation

Create a basic Meteor application:
mrt create Velocity3dDemo
cd Velocity3dDemo
rm -rf Velocity3dDemo*
Import packages:
mrt add coffeescript
mrt add jade
mrt add stylus
mrt add velocityjs
Create a basic web app structure:
mkdir -p client/stylesheets
Create the Stylus file client/stylesheets/app.styl:
@import 'nib'

  padding: 0
  margin: 0

  background-color: #060b14
  overflow: hidden
  color: #ffffff
  font-family: Helvetica Neue, Open Sans, sans-serif
  font-weight: 100

  color: #4bc2f1
  text-decoration: none
    text-decoration: underline

  perspective: 50px
  transform-origin: 50% 100%
  pointer-events: none
  opacity: 0.55

  position: fixed
  width: 22rem
  left: 50%
  top: 45%
  margin-top: -1rem
  margin-left: -11rem
  font-weight: 200
  opacity: 0.65
  text-align: center
  font-size: 0.775rem
  line-height: 1.05rem
  letter-spacing: 0.135em
  word-spacing: -0.075rem

@media screen and (max-width: 400px)
    font-size: 0.45rem !important

  position: fixed
  right: 0.75rem
  bottom: 0.65rem
  cursor: pointer
  text-decoration: none
  color: #d6d6d6
  font-size: 2rem
  letter-spacing: 0.025em

  color: #d74580

  position: fixed
  width: 30px
  height: 30px
  border-radius: 30px
  background-color: #4bc2f1
Create the Jade file client/index.jade:
  title Velocity 3D demo

  #welcome No WebGL. No Canvas. Just pure DOM.
  a#logo(href='http://julian.com/research/velocity/') Velocity.js
Create the CoffeeScript file client/index.coffee:
Template.index.rendered = ->
  # Device detection
  isWebkit = /Webkit/i.test navigator.userAgent
  isChrome = /Chrome/i.test navigator.userAgent
  isMobile = window.ontouchstart isnt undefined
  isAndroid = /Android/i.test navigator.userAgent
  isIE = document.documentMode

  # Redirection
  if isMobile and isAndroid and not isChrome
    alert 'Use Chrome on Android'

  # Helpers
  # Randomly generate an integer between 2 numbers.
  r = (min, max) ->
    Math.floor(Math.random() * (1 + max - min)) + min

  # Dot creation
  # Differentiate dot counts on based on device and browser capabilities
  dotsCount = if isMobile then (if isAndroid then 40 else 60) else ( if isChrome then 175 else 125)
  dotsHtml = ''
  for i in [0..dotsCount]
    dotsHtml += '<div class="dot"></div>'
  $dots = $ dotsHtml

  # Setup
  $container = $ '#container'
  $welcome = $ '#welcome'

  screenWidth = window.screen.availWidth
  screenHeight = window.screen.availHeight
  chromeHeight = screenHeight - (document.documentElement.clientHeight or screenHeight)

  translateZMin = - 725
  translateZMax = 600

  containerAnimationMap =
    perspective: [215, 50]
    opacity: [0.90, 0.55]

  # IE10+ produce odd glitching issues when you rotateZ on a parent element subjected to 3D transforms.
  containerAnimationMap.rotateZ = [5, 0] if not(isIE)

  # Animation
  # Fade out the welcome message.
      opacity: [0, 0.65]
      display: 'none'
      delay: 3500
      duration: 1100
  # Animate the dot's container.
    .css 'perspective-origin', "#{screenWidth/2}px #{(screenHeight*0.45)-chromeHeight}px"
    .velocity containerAnimationMap, {duration: 800, loop: 1, delay: 3250}

  # Special visual enhancement for WebKit browsers which are faster at box-shadow manipulation
  ($dots.css 'boxShadow', '0px 0px 4px 0px #4bc2f1') if isWebkit

        translateX: [
          -> '+=' + r -screenWidth/2.5, screenWidth/2.5
          -> r 0, screenWidth
        translateY: [
          -> '+=' + r -screenHeight/2.75, screenHeight/2.75
          -> r 0, screenHeight
        translateZ: [
          -> '+=' + r translateZMin, translateZMax
          -> r translateZMin, translateZMax
        opacity: [
          -> Math.random()
          -> Math.random() + 0.1
        duration: 6000
        easing: 'easeInOutsine'
    .velocity 'reverse', {easing: 'easeOutQuad'}
        opacity: 0
        duration: 2000
        complete: ->
            .html "<a href='https://www.youtube.com/watch?v=MDLiVB6g2NY&hd=1'>Watch the making of this demo.</a><br /><br />Go create something amazing.<br />Sincerely, <a href='http://twitter.com/shapiro'>@Shapiro</a>"
                opacity: 0.75
                duration: 3500
                display: 'block'
    .appendTo $container
Launch it:
Publish it:
mrt deploy velocity3ddemo.meteor.com
Side note: I've just redeploy this little web app with a link to Meteor. My browser was on the page. Automatically, my browser has been informed that a new release of the code was available. It has only reloaded the modified assets. This is the incredible power of the live reload even when your apps are deployed. Amazing.

The original tutorial

Julian Shapiro, the author of Velocity.js, has provided a very nice Youtube channel which describes how he achieves his demo. A must watch.