Docsets are offline and searchable docs that you can browse using Dash. Recently, Meteor's docset has been added. Now, even when you are offline, you can easily browse your favorite framework's docs.
You can even call Dash within Vim using the Vimdash plugin.
4 juin 2014
1 juin 2014
Velocity.js and Meteor
Introduction
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: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 velocityjsCreate a basic web app structure:
mkdir -p client/stylesheetsCreate the Stylus file
client/stylesheets/app.styl:@import 'nib'
*
padding: 0
margin: 0
body
background-color: #060b14
overflow: hidden
color: #ffffff
font-family: Helvetica Neue, Open Sans, sans-serif
font-weight: 100
a
color: #4bc2f1
text-decoration: none
&:hover
text-decoration: underline
#container
perspective: 50px
transform-origin: 50% 100%
pointer-events: none
opacity: 0.55
#welcome
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)
#welcome
font-size: 0.45rem !important
#logo
position: fixed
right: 0.75rem
bottom: 0.65rem
cursor: pointer
text-decoration: none
color: #d6d6d6
font-size: 2rem
letter-spacing: 0.025em
#logoDot
color: #d74580
.dot
position: fixed
width: 30px
height: 30px
border-radius: 30px
background-color: #4bc2f1
Create the Jade file client/index.jade:head
title Velocity 3D demo
body
+index
template(name='index')
#welcome No WebGL. No Canvas. Just pure DOM.
a#logo(href='http://julian.com/research/velocity/') Velocity.js
#container
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.
$welcome.velocity
opacity: [0, 0.65]
,
display: 'none'
delay: 3500
duration: 1100
# Animate the dot's container.
$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
$dots
.velocity
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'}
.velocity
opacity: 0
,
duration: 2000
complete: ->
$welcome
.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>"
.velocity
opacity: 0.75
,
duration: 3500
display: 'block'
.appendTo $container
Launch it:mrtPublish it:
mrt deploy velocity3ddemo.meteor.comSide 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.31 mai 2014
htop, a better CLI process viewer
Inside my CLI, I sometime like to see which process eats up my CPU or my RAM.
Install it on OSX using:
top is generally a nice utility for that kind of tasks. But, there is a better and cleaner alternative: htop. A comparison picture is worth a thousand words.Install it on OSX using:
brew install htop
25 mai 2014
Famo.us polaroid tutorial in CoffeeScript and within Meteor
Introduction
Since Famo.us v0.2.0, some new tutorials have been added to the Famo.us University. The 1st available project is a Polaroid tutorial which teaches you how to create your own app and widget with Famo.us. Just play this little video to check how incredible the animations are with plain simple HTML5 technologies. Note that, this example is completely responsive and I've tested it on smartphones, tablets and desktops.
This example project is not just beautiful. It works very well in iOS, Chrome on Android, Chrome, Safari and Opera. There are little flickers on Firefox but it seems more due to the browser than to the framework. Though, it is completely useable. As ever, the stock Android browser is definitely a knightmare. Meaning that, if you plan on encapsulating your WebApp in a native browser, Apache Cordova is the way to go for iOS but you will need to encapsulate Chromium if you plan on shipping your WebApp for Android. This can be achieve with projects such as Crosswalk, for instance.
Though, the tutorial is incredibly nice and goes smoothly over every difficulties that you may encounter (one of the best tutorial, that I've seen so far), I didn't choose the same way as described. Actually, JavaScript's inheritance model is such a pain to write, that I prefer avoiding it as much as I can. Thus, I've recreated it using another set of tools and it runs as smoothly as the original:
- CoffeeScript as a replacement of JavaScript.
- Jade as a replacement of HTML.
- Stylus as a replacement of CSS.
- Meteor as a replacement of LiveReload, Express and Grunt.
The result is a very small set of code that produces the same WebApp in a fraction of the necessary code and installation steps.
Configuring your Meteor project
Create your Meteor project with the dead simple following command:meteor create Polaroid cd PolaroidNow create a common fullstack JS directory structure only targeted for a client WebApp without server side integration:
mkdir -p client/lib client/models client/startup client/stylesheets client/views lib packages public/imgRemove the automatically created files:
rm -rf Polaroid.*Add the following package with Meteor:
meteor add coffeescript meteor add stylusAnd this one with Meteorite:
mrt add jade mrt add famonoEasy as pie.
Get the unique required asset from Famo.us
This example WebApp needs a simplepublic/img/camera.png that you'll find in the Zip file that Famo.us provides in their download section.
Create your style file
The style fileclient/stylesheets/app.styl is kept as its minimum as most of the CSS rules are handled by Famo.us.
@import 'nib' html background: #404040 body -webkit-touch-callout: none user-select: none font-family: 'AvenirNext-Medium'
Create your HTML file with Jade
As before for the style file, the main HTML fileclient/index.jade is kept as its minimum as most of the tags are handled by Famo.ushead title Famo.us Polaroid body +index template(name='index')That's it, a simple
template loaded by Meteor.
Create some namespaces
I like to isolate my code from the code that I import. Thus, I create 2 namespaces in 2 separate files.-
One is dedicated to the WebApp in
client/lib/polaroid.coffee:# Declare Polaroid namespace window.Polaroid ?= {} -
The other one is dedicated to Famo.us in
client/lib/famous.coffee:# Declare Famo.us namespace window.Famous ?= {}
lib directory is used as it is loaded first by Meteor.
The model, a Picasa album
With this example, we do not leverage the power of the full JS stack that Meteor provides. We only use its features of live reloading the code and its easy to use build capability. The model is the same as the one provided in the Famo.us Zip file that you've downloaded except that it is created as a CoffeeScript file namedclient/models/slidedata.coffee:Polaroid.SlideData =
userId: "109813050055185479846"
albumId: "6013105701911614529"
picasaUrl: "https://picasaweb.google.com/data/feed/api/user/"
queryParams: "?alt=json&hl=en_US&access=visible&fields=entry(id,media:group(media:content,media:description,media:keywords,media:title))"
defaultImage: "https://lh4.googleusercontent.com/-HbYp2q1BZfQ/U3LXxmWoy7I/AAAAAAAAAJk/VqI5bGooDaA/s1178-no/1.jpg"
getUrl: ->
@picasaUrl + @userId + "/albumid/" + @albumId + @queryParams
parse: (data) ->
urls = []
data = JSON.parse(data)
entries = data.feed.entry
i = 0
while i < entries.length
media = entries[i].media$group
urls.push media.media$content[0].url
i++
urls
A simple dictionary with 2 methods.
Requiring the Famo.us libraries
I simply load all the Famo.us libraries in a single location. This drastically reduces the amount of code. I use the same fileclient/startup/famous.coffee to load the polyfills and to create the Famo.us's singleton so that if I enhance this WebApp with multiple page loaded with a router, there will be no additional loadings or instantiations.
# Import famous.css 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.View = require 'famous/core/View' Famous.Transform = require 'famous/core/Transform' Famous.Surface = require 'famous/core/Surface' Famous.StateModifier = require 'famous/modifiers/StateModifier' Famous.Timer = require 'famous/utilities/Timer' Famous.ImageSurface = require 'famous/surfaces/ImageSurface' Famous.ContainerSurface = require 'famous/surfaces/ContainerSurface' Famous.Lightbox = require 'famous/views/Lightbox' Famous.Utility = require 'famous/utilities/Utility' Famous.Easing = require 'famous/transitions/Easing' Famous.ContainerSurface = require 'famous/surfaces/ContainerSurface' Famous.Transitionable = require 'famous/transitions/Transitionable' Famous.SpringTransition = require 'famous/transitions/SpringTransition' # Register transitions Famous.Transitionable.registerMethod 'spring', Famous.SpringTransition # Create main context Polaroid.mainCtx = Famous.Engine.createContext()
Instantiate the main template
The content of the main template is set under theclient/index.coffee that goes along with our Jade file:Template.index.rendered = ->
# Get request to Picasa API
Famous.Utility.loadURL Polaroid.SlideData.getUrl(), (data) ->
data = Polaroid.SlideData.parse data
# Instantiate the AppView with our URL's data
Polaroid.appView = new Polaroid.AppView data: data
Polaroid.mainCtx.add Polaroid.appView
Creating the views
The rest of this tutorial is pretty close to the one from the Famo.us University except that it uses the object model provided by CoffeeScript instead of the one from JavaScript. You should fill this 3 files while following the tutorial from the Famo.us University so that you get the nice explanations that they provided us.The views are composed of 3 files:
client/views/appview.coffee$(document).ready -> class Polaroid.AppView extends Famous.View DEFAULT_OPTIONS: data: undefined cameraWidth: 0.6 * window.innerHeight constructor: (@options) -> @DEFAULT_OPTIONS.slideWidth = 0.8 * @DEFAULT_OPTIONS.cameraWidth @DEFAULT_OPTIONS.slideHeight = @DEFAULT_OPTIONS.slideWidth + 40 @DEFAULT_OPTIONS.slidePosition = 0.77 * @DEFAULT_OPTIONS.cameraWidth @constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS super @options @createCamera() @createSlideshow() createCamera: -> camera = new Famous.ImageSurface size: [@options.cameraWidth, true] content: 'img/camera.png' properties: width: '100%' cameraModifier = new Famous.StateModifier origin: [0.5, 0] align: [0.5, 0] transform: Famous.Transform.behind @add(cameraModifier).add camera createSlideshow: -> slideshowView = new Polaroid.SlideshowView size: [@options.slideWidth, @options.slideHeight] data: @options.data slideshowModifier = new Famous.StateModifier origin: [0.5, 0] align: [0.5, 0] transform: Famous.Transform.translate 0, @options.slidePosition, 0 slideshowContainer = new Famous.ContainerSurface properties: overflow: 'hidden' @add(slideshowModifier).add slideshowContainer slideshowContainer.add slideshowView slideshowContainer.context.setPerspective 1000client/views/slideshowview.coffee$(document).ready -> class Polaroid.SlideshowView extends Famous.View DEFAULT_OPTIONS: size: [450, 500] data: undefined lightboxOpts: inOpacity: 1 outOpacity: 0 inOrigin: [0, 0] outOrigin: [0, 0] showOrigin: [0, 0] inTransform: Famous.Transform.thenMove Famous.Transform.rotateX(0.9), [0, -300, -300] outTransform: Famous.Transform.thenMove Famous.Transform.rotateZ(0.7), [0, window.innerHeight, -1000] inTransition: duration: 500, curve: Famous.Easing.outBack outTransition: duration: 350, curve: Famous.Easing.inQuad constructor: (@options) -> @constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS super @options @rootModifier = new Famous.StateModifier size: @options.size origin: [0.5, 0] align: [0.5, 0] @mainNode = @add @rootModifier @createLightbox() @createSlides() createLightbox: -> @lightbox = new Famous.Lightbox @options.lightboxOpts @mainNode.add @lightbox createSlides: => @slides = [] @currentIndex = 0 console.log @options.data for url in @options.data slide = new Polaroid.SlideView size: @options.size photoUrl: url @slides.push slide slide.on 'click', @showNexSlide @showCurrentSlide() showCurrentSlide: -> @ready = false slide = @slides[@currentIndex] @lightbox.show slide, => @ready = true slide.fadeIn() showNexSlide: => return if @ready isnt true @currentIndex++ if @currentIndex is @slides.length @currentIndex = 0 @showCurrentSlide()client/views/slideview.coffee$(document).ready -> class Polaroid.SlideView extends Famous.View DEFAULT_OPTIONS: size: [400, 450] filmBorder: 15 photoBorder: 3 photoUrl: Polaroid.SlideData.defaultImage angle: -0.5 constructor: (@options) -> @constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS super @options @rootModifier = new Famous.StateModifier size: @options.size @mainNode = @add @rootModifier @createBackground() @createFilm() @createPhoto() createBackground: -> background = new Famous.Surface properties: backgroundColor: '#fffff5' boxShadow: '0 10px 20px -5px rgba(0, 0, 0, 0.5)' cursor: 'pointer' @mainNode.add background background.on 'click', => @_eventOutput.emit 'click' createFilm: -> @options.filmSize = @options.size[0] - 2 * @options.filmBorder film = new Famous.Surface size: [@options.filmSize, @options.filmSize] properties: backgroundColor: '#222' zIndex: 1 # Make surface invisible to pointer events pointerEvents: 'none' filmModifier = new Famous.StateModifier origin: [0.5, 0] align: [0.5, 0] transform: Famous.Transform.translate 0, @options.filmBorder, 1 @mainNode .add filmModifier .add film createPhoto: -> photoSize = @options.filmSize - 2 * @options.photoBorder photo = new Famous.ImageSurface size: [photoSize, photoSize] content: @options.photoUrl properties: zIndex: 2 # Make surface invisible to pointer events pointerEvents: 'none' @photoModifier = new Famous.StateModifier origin: [0.5, 0] align: [0.5, 0] transform: Famous.Transform.translate 0, @options.filmBorder + @options.photoBorder, 2 opacity: 0.01 @mainNode .add @photoModifier .add photo fadeIn: => @photoModifier.setOpacity 1, {duration: 1500, curve: 'easeIn'} @shake() shake: -> @rootModifier.halt() @rootModifier.setTransform Famous.Transform.rotateX(@options.angle), {duration: 200, curve: 'easeOut'} @rootModifier.setTransform Famous.Transform.identity, {method: 'spring', period: 600, dampingRatio: 0.15}
Further words
My integration is not as proper as I would like it to be. Each class declaration relies on a ready event that I did not succeed in removing. Identically, my class constructors call their parent's one explicitly. Feel free to post some comments if you have a better integration.Preview markdown in your finder
Sidre Sorhus has created an interesting set of QuickLook plugins for the OSX's Finder. Among them, there is a Markdown previewer. Very handy. Install these plugins with this command:
brew cask install qlcolorcode qlstephen qlmarkdown quicklook-json qlprettypatch quicklook-csv betterzipql webp-quicklook suspicious-package
22 mai 2014
Never cry again after an unfortunate "rm -rf"
Sidresorhus has just published an awesome package named trash. This little CLI command delete your files and folders by moving them into your OS's trashcan. Beside being a secure
It supports Windows, OSX and Linux.
rm command, it simplifies it when you are removing a tree of files. Super nice.It supports Windows, OSX and Linux.
18 mai 2014
The Cult of Gulp: Independent preprocessor for Gulp
In a former post (A gulp of coffee: your gulpfile in coffeescript), I've shown how to bootstrap CoffeeScript in Gulp. There is now a far better solution than mine that does not require any additional file: Cult.
This little CLI just analyse the extension and automatically requires the right REPL. A time saver!
This little CLI just analyse the extension and automatically requires the right REPL. A time saver!
Inscription à :
Articles (Atom)


