19 juil. 2014

Do we need HTML and CSS when we got JavaScript or more? A case for AbsurdJS, Meteor, Famo.us and CoffeeScript.

Introduction

AbsurdJS is an amazing project. What is it about? A processor for your HTML and CSS in JavaScript. In JSON to be more precise.

The problem

CSS was invented for designers. But do you really know that much designers that are able to provide you with a nice CSS rules that will be awesome on all screens? You are favored by gods if it is your case. Most of the time, they will provide you with some PSD (what an ugly form of design), AI (if you are lucky), Sketch or SVG (here, it is not anymore based on luck, it is like having an angel upon your shoulders).

The same goes with HTML. Semantics that appears with HTML5 were added for SEO. But do you know that much SEO guys that will give you the right HTML code? I haven't seen any in my whole 20 years on the web carrier(though SEO is not that long of a job).

Thus, why are we using 3 languages for writing our codes. Is that right? Do we have to? Is it done for helping us and keeping separation of concerns? Funny. Patterns like this exists since the dawn of design patterns from the GoF. And what if we need to synchronize this HTML, CSS and JS back together for animations purposes? We request back in our code the HTML tags that we have just declared? We hooks on the CSS? If we need a color theme, do we have to write it twice or more? Funny, too. Even media queries for responsive web designs, seems like an odd way of reproducing the abstract factory pattern (or the bridge depending on if you know to who you are distributing your files).

The solutions

There are many. Generally, I was keen on using preprocessors: SASS, LESS, Stylus, YAML, Jade, Blade, CoffeeScript, Typescript, Dart, ... But, it finally does not give me a proper answer to the problems previously mentioned. It still need glue code to make all of this work together properly. Things started to shape up when I end up using MeteorFamo.us and Velocity.js. The Blaze component of Meteor is transforming your HTML, more precisely, your HTML templates using Spacebar, a derivative of Mustache, into JS code. The same goes with Famo.us. It creates HTML and CSS rules that plays well together so that they limit layout trashing issues and combines this technics with advanced physic and animation engine. The same goes with Velocity.js. This jQuery plugins brings back synchronized CSS animations in with JS.

Still, plain vanilla JavaScript is a pain to write. While there are plenty of transpilers that could lessen the burden (like Dart and Typescript, to mention the most used ones), none have proven to be as easy as CoffeeScript to me.

Conclusion

Now the solution starts to shape up. Why not use the power of AbsurdJS, Meteor, Famo.us and CoffeeScript? This combination would be a real full stack. It would goes from the persistance layer, the application server to the front end with one and only one language. A transpiled one that even lessen the number of lines that you need to write.

14 juil. 2014

Jade within Atom.io: Fasten your HTML and SVG authoring and template debugging

When writing HTML, XML, SVG or templates based on this language, it is cumbersome to open and close tags. Even with a good editor that closes tags for you or a good plugin that write snippet codes, you end up with unreadable and long source files. Jade removes this hassle by providing a simple and elegant code that transpiles to tagged code.

Here's an example of Jade transpiled to HTML:

However, it is sometime handy to seen what your generated code will look like. I've published another Atom.io plugin that preview the generated results with ctrl+alt+j.

The package is available on Atom.io's repository: https://atom.io/packages/jade-compile
And its code source is available on Github: https://github.com/PEM--/jade-compile

9 juil. 2014

Meteor.js from within Atom.io: Full stack dev with live reload in one key combo

I've just published a simple Meteor plugin for Atom.io. It launches  Meteor with ctrl+alt+m. Whenever any problem is found on the server, a pane shows up from a dedicated status bar to warn you that something is going wrong.

The package is available on Atom.io's repository: https://atom.io/packages/meteor-helper
And its code source is available on Github: https://github.com/PEM--/meteor-helper

Here's a nice and simple video showing what it brings:

4 juil. 2014

14 juin 2014

Some bubbles with Famo.us's physic engine in CoffeeScript and Meteor.js

Introduction

A week ago, Raix, the author of Famono package used for integrating Require.js and Famo.us with Meteor.js, has published a new release that simplifies greatly the integration.

I was willing to demonstrate just that when a nice demo of Famo.us's physic engine has shown up on my radar: http://hbsand.com/HappyBoxes/. So why not demonstrating both?


You can access the live demo here: http://famousbubble.meteor.com/.
You can also clone the code repository from Github: https://github.com/PEM--/famousbubble

Note for Chrome users on OSX : The current release of Chrome, the 36, has a bug that stops the demo running after ~1-2s. This bug is fixed in Chrome Canary version 37. I didn't see it on the current Chrome for Android or iOS. Firefox and Safari work well on OSX.

Preparing your development environment

I suppose that you have already install Node.jsMeteor.js and Meteorite on your system. 

So, lets get down to business. The first step is to create the app:
mrt create FamousBubble
cd FamousBubble
rm -rf FamousBubble.*
mkdir -p client/stylesheets client/startup client/views
mrt add coffeescript
mrt add stylus
mrt add jade
mrt add famono

For the imported Require.js package, I keep it at the bare minimum. Famono places the imported packages from a file called client/lib/smart.require:
{
  "famous": {
    "git": "https://github.com/Famous/famous.git"
  },
  "famousPolyfills": {
    "git": "https://github.com/Famous/polyfills.git"
  }
}
This has not changed from the early version.

Linking Famo.us with Meteor.js

In Famono, what has changed is the way you require your dependencies. The client/startup/famous.coffee is greatly reduced:
# This is equivalent to: require 'famousPolyfills'
famousPolyfills
# Identically, this is equivalent to: require 'famous.core.famous'
famous.core.famous
# Declaring the main context
window.mainCtx = famous.core.Engine.createContext()

Everything is now imported into the main context of Meteor.js. There is no more boilerplate code.

Our main Jade file, client/index.jade stays unchanged:
head
  title Famo.us - Physic demo
  meta(name='viewport', content='width=device-width, maximum-scale=1, user-scalable=no')
  meta(name='mobile-web-app-capable', content='yes')
  meta(name='apple-mobile-web-app-capable', content='yes')
  meta(name='apple-mobile-web-app-status-bar-style', content='black')

body
  +index

template(name='index')

The Styus file, client/stylesheets/app.styl, is also unchanged:
@import nib

html
  font-family: Helvetica, Arial, sans-serif

*
  -webkit-user-drag: none

body
  -webkit-user-callout: none
  user-select: none
  background-color: #FF851B

Like the former file, the associated CoffeeScript file client/index.coffee to the index template is almost unchanged either:
Template.index.rendered = ->
  $(document).ready ->
    window.appView = new AppView()
    mainCtx.add appView
    appView.addDragger()
    appView.addBubbles()

Easier subclassing

As the Famo.us's University told us, you create your views by inheriting from Famo.us's ones. With Famono, it is now simplified. Here the code for the AppView, client/views/AppView.coffee that we just call in the previous file, the index template:
class @AppView extends famous.core.View
  DEFAULT_OPTIONS:
    numBodies: 10
    gravity: [0, 0.0015, 0]
  constructor: (@options)->
    @constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS
    super @options
    surf = new famous.core.Surface
      size: [400, 400]
      properties:
        backgroundColor: '#FFDC00'
        borderRadius: '8px'
    mod = new famous.core.Modifier
      origin: [.5, .5]
    @add(mod).add surf
    @gravity = new famous.physics.forces.Force @options.gravity
    @ceiling = new famous.physics.constraints.Wall
      normal: [0, 1, 0]
      distance: 200
      restitution: 0
    @floor = new famous.physics.constraints.Wall
      normal: [0, -1, 0]
      distance: 200
      restitution: 0
    @left = new famous.physics.constraints.Wall
      normal: [1, 0, 0]
      distance: 200
      restitution: 0
    @right = new famous.physics.constraints.Wall
      normal: [-1, 0, 0]
      distance: 200
      restitution: 0
    @pe = new famous.physics.PhysicsEngine()
    @collision = new famous.physics.constraints.Collision restitution: 0
    @bubbleBodies = []
    famous.inputs.GenericSync.register
      'mouse': famous.inputs.MouseSync
      'touch': famous.inputs.TouchSync
  addDragger: ->
    @dragger = new Dragger()
    @pe.addBody @dragger.body
    (@_add @dragger.state).add @dragger.shape
    sync = new famous.inputs.GenericSync ['mouse', 'touch']
    @dragger.shape.pipe sync
    sync.on 'update', (data) =>
      @dragger.position[0] += data.delta[0]
      @dragger.position[1] += data.delta[1]
      @dragger.body.setPosition @dragger.position

  addBubble: (i) =>
    bubble = new Bubble()
    @pe.addBody bubble.body
    bubble.state.transformFrom =>
      @gravity.applyForce bubble.body
      bubble.body.getTransform()
    (@add bubble.state).add bubble.shape
    @pe.attach [@right, @left, @floor, @ceiling], bubble.body
    (@pe.attach @collision, @bubbleBodies, bubble.body) if i > 0
    @pe.attach @collision, [bubble.body], @dragger.body
    @bubbleBodies.push bubble.body

  addBubbles: ->
    [0...@options.numBodies].map (i) =>
      famous.utilities.Timer.setTimeout (@addBubble.bind @, i), 1000
As you can see it, the inheritance from a Famo.us's View does not require you to wait for Famo.us to be loaded in your document. Additionally, the require step has been greatly simplified. Calling any class provided by Famo.us is done with a simple namespaced call.

I've create 2 more classes. The first one, client/views/Dragger.coffee concerns the little dragging bubble used to play with the blue bubbles:
class @Dragger
  RADIUS: 30
  constructor: ->
    @shape = new famous.core.Surface
      size: [2 * @RADIUS, 2 * @RADIUS]
      properties:
        border: '2px solid #FF4136'
        borderRadius: "#{2 * @RADIUS}px"
        backgroundColor: 'rgba(255, 255, 255, 0.5)'
    @body = new famous.physics.bodies.Circle
      radius: @RADIUS
      mass: 5
    @position = [0, 0]
    @state = new famous.core.Modifier
      origin: [.5, .5]
      transform: =>
        famous.core.Transform.translate @position[0], @position[1], 0

The second one, client/view/Bubble.coffee concerns the bubble themselves:
class @Bubble
  constructor: ->
    radius = famous.math.Random.integer 20, 60
    @shape = new famous.core.Surface
      size: [radius * 2, radius * 2]
      properties:
        backgroundColor: '#7FDBFF'
        border: '3px solid #0074D9'
        borderRadius: "#{radius}px"
    @body = new famous.physics.bodies.Circle radius: radius, mass: 2
    @state = new famous.core.Modifier origin: [.5, .5]

Conclusion

With the new Famono release, integrating Famo.us and Meteor.js is simpler than ever. My little sample is missing few things. A better separation of the controller from the views would be great. But, there is some upcoming Famo.us lessons that should arrive in the Famo.us's University. Therefore, they will surely cover their best practices. No rush.

9 juin 2014

Timbre demo from Famo.us University using Meteor.js and CoffeeScript

Introduction

As already demonstrated in my previous article Famo.us polaroid tutorial in CoffeeScript and within MeteorMeteor, CoffeeScript and Famo.us are incredibly useful tools for front end or full stack developers. This article just show the same principles with the Famo.us University Timbre tutorial. A live demo is deployed on Meteor's testing ground: http://famoustimbre.meteor.com/.

Show me the code, please

If you find yourself stuck at translating some JS concept to CoffeeScript while playing the nice tutorial from Famo.us University, I provide my code hereafter:
client/stylesheets/app.styl
@import nib

html
  font-family: Helvetica

*
  -webkit-user-drag: none

body
  -webkit-touch-callout: none
  user-select: none

client/index.jade
head
  title Famo.us Timbre
  meta(name='viewport', content='width=device-width, maximum-scale=1, user-scalable=no')
  meta(name='mobile-web-app-capable', content='yes')
  meta(name='apple-mobile-web-app-capable', content='yes')
  meta(name='apple-mobile-web-app-status-bar-style', content='black')
body
  +index

template(name='index')

client/lib/famous.coffee
window.Famous ?= {}

client/lib/timbre.coffee
window.Timbre ?= {}

client/startup/famous.coffee
# Import Famous
require 'famous/core/famous'
# Adds the famo.us dependencies
require 'famous-polyfills'
# Wait for document ready
$(document).ready ->
  # Load Famo.us libraries
  Famous.Engine           = require 'famous/core/Engine'
  Famous.Surface          = require 'famous/core/Surface'
  Famous.Transform        = require 'famous/core/Transform'
  Famous.View             = require 'famous/core/View'
  Famous.Modifier         = require 'famous/core/Modifier'
  Famous.StateModifier    = require 'famous/modifiers/StateModifier'
  Famous.HeaderFooter     = require 'famous/views/HeaderFooterLayout'
  Famous.ImageSurface     = require 'famous/surfaces/ImageSurface'
  Famous.FastClick        = require 'famous/inputs/FastClick'
  Famous.GenericSync      = require 'famous/inputs/GenericSync'
  Famous.MouseSync        = require 'famous/inputs/MouseSync'
  Famous.TouchSync        = require 'famous/inputs/TouchSync'
  Famous.GenericSync.register
    'mouse': Famous.MouseSync
    'touch': Famous.TouchSync
  Famous.Easing           = require 'famous/transitions/Easing'
  Famous.Transitionable   = require 'famous/transitions/Transitionable'
  Famous.Timer            = require 'famous/utilities/Timer'
  # Create main context
  Timbre.mainCtx = Famous.Engine.createContext()

client/models/StripData.coffee
Timbre.StripData = [
  {title: 'search', iconUrl: 'img/strip-icons/famous.png'}
  {title: 'starred', iconUrl: 'img/strip-icons/starred.png'}
  {title: 'friends', iconUrl: 'img/strip-icons/friends.png'}
  {title: 'settings', iconUrl: 'img/strip-icons/settings.png'}
]

client/index.coffee
ASPECT_RATIO = 320 / 548

Template.index.rendered = ->
  $document = $ document
  $document.ready ->
    docwidth = $document.width()
    docheight = $document.height()
    if docwidth / ASPECT_RATIO > docheight
      screenwidth = docheight * ASPECT_RATIO
      screenheight = docheight
    else
      screenwidth = docwidth
      screenheight = docwidth / ASPECT_RATIO
    appView = new Timbre.AppView()
    mainMod = new Famous.Modifier
      size: [screenwidth, screenheight]
    Timbre.mainCtx
      .add mainMod
      .add appView

client/models/AppView.coffee
$(document).ready ->
  class Timbre.AppView extends Famous.View
    DEFAULT_OPTIONS:
      openPosition: 276
      transition:
        duration: 300
        curve: Famous.Easing.inOutBack
      posThreshold: 138
      velTreshold: 0.75
    constructor: (@options) ->
      @constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS
      super @options
      @menuToggle = false
      @pageViewPos = new Famous.Transitionable 0
      @createPageView()
      @createMenuView()
      @setListeners()
      @handleSwipe()
    createPageView: ->
      @pageView = new Timbre.PageView()
      @pageModifier = new Famous.Modifier
        transform: =>
          Famous.Transform.translate @pageViewPos.get(), 0, 0
      @add(@pageModifier).add @pageView
    createMenuView: ->
      @menuView = new Timbre.MenuView stripData: Timbre.StripData
      menuModifier = new Famous.StateModifier
        transform: Famous.Transform.behind
      @add(menuModifier).add @menuView
    setListeners: ->
      @pageView.on 'menuToggle', @toggleMenu
    toggleMenu: =>
      if @menuToggle
        @slideLeft()
      else
        @slideRight()
        @menuView.animateStrips()
      @menuToggle = !@menuToggle
    slideLeft: ->
      @pageViewPos.set 0, @options.transition, =>
        @menuToggle = false
    slideRight: ->
      @pageViewPos.set @options.openPosition, @options.transition, =>
        @menuToggle = true
    handleSwipe: ->
      sync = new Famous.GenericSync(
        ['mouse', 'touch']
      , {direction: Famous.GenericSync.DIRECTION_X}
      )
      @pageView.pipe sync
      sync.on 'update', (data) =>
        currentPosition = @pageViewPos.get()
        @pageViewPos.set Math.max 0, currentPosition + data.delta
        if currentPosition is 0 and data.velocity > 0
          @menuView.animateStrips()
      sync.on 'end', (data) =>
        velocity = data.velocity
        position = @pageViewPos.get()
        if position > @options.posThreshold
          if velocity < -@options.velTreshold
            @slideLeft()
          else
            @slideRight()
        else
          if velocity > @options.velTreshold
            @slideRight()
          else
            @slideLeft()

client/models/PageView.coffee
$(document).ready ->
  class Timbre.PageView extends Famous.View
    DEFAULT_OPTIONS:
      headerSize: 44
    constructor: (@options) ->
      @constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS
      super @options
      @createLayout()
      @createHeader()
      @createBody()
      @setListeners()
    createLayout: ->
      @layout = new Famous.HeaderFooter
        headerSize: @options.headerSize
      layoutModifier = new Famous.StateModifier
        transform: Famous.Transform.translate 0, 0, .1
      @add(layoutModifier).add @layout
    createHeader: ->
      backgroundSurface = new Famous.Surface
        properties: backgroundColor: 'black'
      backgroundModifier = new Famous.StateModifier
        transform: Famous.Transform.behind
      @layout.header
        .add backgroundModifier
        .add backgroundSurface
      @hamburgerSurface = new Famous.ImageSurface
        size: [44, 44]
        content: 'img/hamburger.png'
      searchSurface = new Famous.ImageSurface
        size: [232, 44]
        content: 'img/search.png'
      iconSurface = new Famous.ImageSurface
        size: [44, 44]
        content: 'img/icon.png'
      hamburgerModifier = new Famous.StateModifier
        origin: [0, .5]
        align: [0, .5]
      searchModifier = new Famous.StateModifier
        origin: [.5, .5]
        align: [.5, .5]
      iconModifier = new Famous.StateModifier
        origin: [1, .5]
        align: [1, .5]
      @layout.header
        .add hamburgerModifier
        .add @hamburgerSurface
      @layout.header
        .add searchModifier
        .add searchSurface
      @layout.header
        .add iconModifier
        .add iconSurface
    createBody: ->
      @bodySurface = new Famous.ImageSurface
        size: [undefined, true]
        content: 'img/body.png'
      @layout.content.add @bodySurface
    setListeners: ->
      @hamburgerSurface.on 'click', =>
        @_eventOutput.emit 'menuToggle'
      @bodySurface.pipe @_eventOutput
    createBacking: ->
      backing = new Famous.Surface
        properties:
          backgroundColor: 'black'
          boxShadow: '0 0 20px rgba(0,0,0,0.5)'
      @add backing

client/models/MenuView.coffee
$(document).ready ->
  class Timbre.PageView extends Famous.View
    DEFAULT_OPTIONS:
      headerSize: 44
    constructor: (@options) ->
      @constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS
      super @options
      @createLayout()
      @createHeader()
      @createBody()
      @setListeners()
    createLayout: ->
      @layout = new Famous.HeaderFooter
        headerSize: @options.headerSize
      layoutModifier = new Famous.StateModifier
        transform: Famous.Transform.translate 0, 0, .1
      @add(layoutModifier).add @layout
    createHeader: ->
      backgroundSurface = new Famous.Surface
        properties: backgroundColor: 'black'
      backgroundModifier = new Famous.StateModifier
        transform: Famous.Transform.behind
      @layout.header
        .add backgroundModifier
        .add backgroundSurface
      @hamburgerSurface = new Famous.ImageSurface
        size: [44, 44]
        content: 'img/hamburger.png'
      searchSurface = new Famous.ImageSurface
        size: [232, 44]
        content: 'img/search.png'
      iconSurface = new Famous.ImageSurface
        size: [44, 44]
        content: 'img/icon.png'
      hamburgerModifier = new Famous.StateModifier
        origin: [0, .5]
        align: [0, .5]
      searchModifier = new Famous.StateModifier
        origin: [.5, .5]
        align: [.5, .5]
      iconModifier = new Famous.StateModifier
        origin: [1, .5]
        align: [1, .5]
      @layout.header
        .add hamburgerModifier
        .add @hamburgerSurface
      @layout.header
        .add searchModifier
        .add searchSurface
      @layout.header
        .add iconModifier
        .add iconSurface
    createBody: ->
      @bodySurface = new Famous.ImageSurface
        size: [undefined, true]
        content: 'img/body.png'
      @layout.content.add @bodySurface
    setListeners: ->
      @hamburgerSurface.on 'click', =>
        @_eventOutput.emit 'menuToggle'
      @bodySurface.pipe @_eventOutput
    createBacking: ->
      backing = new Famous.Surface
        properties:
          backgroundColor: 'black'
          boxShadow: '0 0 20px rgba(0,0,0,0.5)'
      @add backing

client/models/StripView.coffee
$(document).ready ->
  class Timbre.StripView extends Famous.View
    DEFAULT_OPTIONS:
      width: 320
      height: 55
      angle: -0.2
      iconSize: 32
      iconUrl: 'img/strip-icons/famous.png'
      title: 'Famo.us'
      fontSize: 26
    constructor: (@options) ->
      @constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS
      super @options
      @createBackground()
      @createIcon()
      @createTitle()
    createBackground: ->
      backgroundSurface = new Famous.Surface
        size: [@options.width, @options.height]
        properties:
          backgroundColor: 'black'
          boxShadow: '0 0 1px rgba(0, 0, 0, 1)'
      rotateModifier = new Famous.StateModifier
        transform: Famous.Transform.rotateZ @options.angle
      skewModifier = new Famous.StateModifier
        transform: Famous.Transform.skew 0, 0, @options.angle
      @add(rotateModifier)
        .add skewModifier
        .add backgroundSurface
    createIcon: ->
      iconSurface = new Famous.ImageSurface
        size: [@options.iconSize, @options.iconSize]
        content: @options.iconUrl
        properties:
          pointerEvents: 'none'
      iconModifier = new Famous.StateModifier
        transform: Famous.Transform.translate 24, 2, 0
      @add(iconModifier).add iconSurface
    createTitle: ->
      titleSurface = new Famous.Surface
        size: [true, true]
        content: @options.title
        properties:
          color: 'white'
          fontSize: "#{@options.fontSize}px"
          textTransform: 'uppercase'
          pointerEvents: 'none'
      titleModifier = new Famous.StateModifier
        transform: Famous.Transform.thenMove(
          Famous.Transform.rotateZ @options.angle
        , [75, -5, 0]
        )
      @add(titleModifier).add titleSurface

8 juin 2014

AdFab makes Badoit sparkling thanks to Famo.us

Famo.us has a physic engine. When used for animating screens, it's simply stunning.