Tuesday, November 13, 2012

HTML5 Polyfills - Fullscreen e RequestAnimationFrame APIs


Até o momento esses são os melhores polyfills para utilizar Fullscreen e RequestAnimationFrame, features de HTML5 em browsers de hoje em dia.

RequestAnimationFrame API

Optimize concurrent animations together into a single reflow and repaint cycle, leading to higher fidelity animation, and using less CPU, GPU, memory, and battery.

http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating

Fullscreen API

Provides an easy way for web content to be presented using the user's entire screen.

https://github.com/sindresorhus/screenfull.js

HTML5 AppCache API - Como prevenir o browser de cachear recursos que não serão utilizados no arquivo de manifesto


The method describe below doesn't work in all browsers.  
For now I'm using two different html files. But the best solution is on server side, making a rewrite rule for redirecting the user to the correct manifest file.


I'm writing a web application that uses the AppCache API for offline browsing. But I'm also using the Audio API to play back-ground music and a few audio effects.

For audio support in different browsers I'm delivering each sound/music in two different file formats: OGG and MP3.

The problem is regarding the cache manifest file. If we add all audio files (MP3 and OGG) in the cache manifest file, all browsers will cache all files. Including the unsupported ones. So, we end up with a huge storage requirement. Which is really bad if you are on a 3G connection for example.

So, to prevent browser caching unsupported resources, the best approach I've found was to split the manifest file. This way we can tell browsers that sopport OGG files to cache only OGG files, and do tha same for other formats like MP3.

Ok then. I have two manifest cache files, one with all OGG files listed (ogg.appcache) and the other one with the MP3 files (mp3.appcache).

Now what!? How do I swap from one to other?

Easy. First we should consider the browser supports OGG. If so, we can add the manifest attribute into the html tag with the right manifest file, just like that:


<html manifest="ogg.appcache">

Now, we have to check if the browser supports MP3. If it does, we change the value of the attribute "manifest" from the html tag. We can do that with this javascript:

var audio = document.createElement('audio');
if(audio.canPlayType('audio/mpeg;'))
  document.documentElement.setAttribute("manifest"document.documentElement.getAttribute("manifest").replace('ogg','mp3'));


jsperf é uma das melhores coisas que eu ví aparecerem neste ano. É uma poderosa engine de testes para Javascript.


jsperf é uma das melhores coisas que eu ví aparecerem neste ano. É uma poderosa engine de testes para Javascript.

Todo teste criado é público e listado lá. Portanto qualquer um pode testar o mesmo código em qualquer plataforma ou browser e todos os resultados são armazenados de forma que quanto mais pessoas rodarem cada teste mais informações para analise teremos.

Para ver como ele funciona e também para responder a uma pergunta relacionada a performance de renderização de textos com sombras na tag canvas, eu criei um teste no jsperf.

http://jsperf.com/requestanimationframe-canvas-drawing-text-shadows

Como eu só testei no Chrome e no Firefox o que eu poso dizer até o momento é:

No 18.0 a performance cai quase pela metade quando desenhamos textos com sombras no canvas.

Já no Firefox 12.0 observei a mesma situação. Mas comparando os resultados entre os dois browsers observei que o Chrome realiza a mesma tarefa que o Firefox na metade do tempo que o seu rival.

Lembre-se de que isso é apenas um simples teste e que eu testei apenas na minha máquina.

Testando softwares


Testando softwares

Antes

  • Desenvolvedores terminam o código e outra equipe se encarrega de testa-lo
  • Código passa por um processo de qualidade “Quality Assurance [QA]”
  • O pessoal de QA manualmente interage com o código

Hoje

  • Teste é parte de cada iteração no código
  • Desenvolvedores são responsáveis por testar o próprio código
  • Ferramentas de teste e processos são automatizados
  • Pessoal de QA e testes aprimora as ferramentas e os cenários de testes


Qualidade de software é o resultado de um bom processo, e não a responsabilidade de um grupo específico.


 

Debug na forma convencional X Test Driven Development



Conventional Debugging vs. TDD

Conventional 

  • Escreva 10 linhas de código, rode, veja o erro e adicione linhas de breaks no debugger
  • Insira linha de printfʼs para imprimir na tela as variáveis enquanto você roda o script repetidamente
  • Pare no debugger, mexa em algumas variáveis para controlar o flow do código
  • Droga! F@#&@#! Tinha certeza de que tinha corrigido isso, agora tenho que fazer isso tudo novamente

TDD

  • Escreva algumas linhas, só que antes de mais nada teste e descubra imediatamente de alguma coisa deu errada
  • Teste pequenas partes do código
  • Utiliza mocks e stubs para controlar o flow do código
  • Rode testes automaticamente

Jogo de quebra-cabeça HTML5 Puzzle agora é um Chrome Experiment


Jogo de quebra-cabeça HTML5 Puzzle agora é um Chrome Experiment


HTML5 Puzzle

Esta é a razão pela qual eu amo cache...


Esta é a razão pela qual eu amo cache...



Touch != mouse


Touch != mouse

  1. Não tem o status hover
  2. Múltiplos pontos
  3. Input menos preciso
  4. Dedos não são coordenadas (x, y), e também possuem formas
  5. Futuro: Pressão? Feedback de tatoHover status?

Desenvolvendo para iOS 5.1.1 no Xcode 4.3 - Testando aplicativos em dispositivos reais sem um "Apple Provisioning Profile"


Desenvolvendo para iOS 5.1.1 no Xcode 4.3 - Testando aplicações em dispositivos reais sem um "Apple Provisioning Profile"

Testando aplicativos em dispositivos reais sem ter um "Apple Provisioning Profile"

Depois de dois longos dias eu consegui compilar e rodar um aplicativo para iOS 5.1.1 do Xcode diretamente para o meu dispositivo sem ter um provisioning profile.


Para fazer isso você precisará de:
  • Jailbroken iPhone, iPad ou iPod
  • Appsync instalado no dispositivo
  • Xcode 4.3+

Passo 1: Criar um novo certificado "self-signed code-signing" usando o utilitário Keychain Access
  • Abra o aplicativo Keychain Access
  • Vá em Menu "Keychain Access" -> "Certificate Assistant" -> "Create a Certificate"
  • Escolha um nome único e fácil de ser lembrado. Você precisará desse nome posteriormente.
  • Escolha a opção "Self Signed Root" para "Identity Type"
  • Escolha "Code Signing" para "Certificate Type"
  • Cheque a opção "Let me override defaults"
  • E clique em "Create"
  • Em seguida clique em "next" para todas as perguntas sem mudar absolutamente nada.

Passo 2: Edite o arquivo "Info.plist" do Xcode
  • Abra o arquivo: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Info.plist
  • Troque as 3 ocorrências da string "XCiPhoneOSCodeSignContext" para "XCCodeSignContext"
  • Salve o arquivo e restarte o Xcode

Passo 3: Instale o Appsync no dispositivo
  • Intale o aplicativo "Appsync" pelo Cydia
  • Intale o aplicativo de "SSH" pelo Cydia
  • Acesse o dispositivo via SSH e crie um arquivo em branco chamdo "tdmtanf" em "/var/mobile"

Passo 4: Configuração do projeto no Xcode
  • Abra o projeto no Xcode
  • Vá em "Project" -> "Build Settings" -> "Code Signing" -> "Code Signing Identity" -> Escolha a identidade relacionada ao certificado que você criou anteriormente no passo 1.
  • Faça a mesma coisa em "Targets" -> "Build Settings" -> "Code Signing" -> "Code Signing Identity"

Agora você pode compilar e rodar esse projeto do Xcode diretamente para o seu dispositivo.


Adsense - Anúncios responsíveis com Bootstrap e CSS @media queries


Adsense - Anúncios responsíveis com Bootstrap e CSS @media queries

O Twitter Bootstrap possuí uma relação de classes em CSS que nos ajuda a implementar diferentes diferentes tamanhos de anúncios para diferentes dispositivos.

ClassPhones767px and belowTablets979px to 768pxDesktopsDefault
.visible-phoneVisible
.visible-tabletVisible
.visible-desktopVisible
.hidden-phoneVisibleVisible
.hidden-tabletVisibleVisible
.hidden-desktopVisibleVisible
Portanto a ideia é utilizar essas classes para mostrar os anúncios nos tamanhos certos para cada tipo de device.

No meu caso eu configurei o seguinte esquema:
  • Padrão Desktop
    • Leaderboard (728x90)


  • Padrão Portrait tablet to landscape and desktop
    • Banner (468x60)

  • Padrão Landscape phone to portrait tablet
    • Banner (468x60)

  • Padrão Landscape phones and down
    • Half Banner (234x60)


É incrivelmente simples de fazer isso usando as classes do Bootstrap. Veja o exemplo:


 <div class="visible-desktop">  
        <script type="text/javascript">  
             google_ad_client = "ca-pub-XXXXXX";  
             google_ad_slot = "XXXXXXX";  
             google_ad_width = 728;  
             google_ad_height = 90;  
        </script>  
        <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>   
 </div>  

 <div class="visible-tablet">  
        <script type="text/javascript">  
             google_ad_client = "ca-pub-XXXXXX";  
             google_ad_slot = "XXXXXXX";  
             google_ad_width = 468;  
             google_ad_height = 60;  
        </script>  
        <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
 </div>  

 <div class="visible-phone">  
        <script type="text/javascript">  
             google_ad_client = "ca-pub-XXXXXX";  
             google_ad_slot = "XXXXXXX";  
             google_ad_width = 234;  
             google_ad_height = 60;  
        </script>  
        <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
 </div>  

Fácil né?

Aqui há um exemplo mostrando como podemos fazer a mesma coisa utilizando apenas Javascript.


Adsense - Anúncios responsíveis via Javascript


Adsense - Anúncios responsíveis via Javascript

Como fazer anúncios responsíveis usando Javascript

A ideia é verificar o tamanho da tela do usuário e em seguida, baseado nos valores, mostrar os anúncios nos tamanhos corretos.

No meu caso eu configurei o seguinte esquema:

  • Padrão Desktop
    • Leaderboard (728x90)

  • Padrão Portrait tablet to landscape and desktop
    • Banner (468x60)

  • Padrão Landscape phone to portrait tablet
    • Banner (468x60)

  • Padrão Landscape phones and down
    • Half Banner (234x60)


Veja o código fonte do exemplo:


 <script type="text/javascript">  
       google_ad_client = "ca-pub-XXXXXX";  
       google_ad_slot = "";  
       if(window.innerWidth >= 800) {  
        //visible-desktop  
        //Medium Rectangle  
        google_ad_slot = "xxxxxxx";  
        google_ad_width = 300;  
        google_ad_height = 250;  
       }  
       else if((window.innerWidth > 480)&&(window.innerWidth < 800)) {  
        //visible-tablet  
        //Square  
        google_ad_slot = "xxxxxxx";  
        google_ad_width = 250;  
        google_ad_height = 250;  
       }  
       else if(window.innerWidth <= 480) {  
        //visible-phone  
        //Large Rectangle  
        google_ad_slot = "xxxxxxx";  
        google_ad_width = 336;  
        google_ad_height = 280;  
       }  
       if(google_ad_slot != "")  
        document.write('1: <scr'+'ipt type=\"text/javascript\" src=\"http://pagead2.googlesyndication.com/pagead/show_ads.js\"></scri'+'pt>');  
       </script>  

Você utiliza o Twitter Bootstrap? Se sim, você pode conseguir o mesmo resultado de maneira muito mais simples. Veja aqui!


Passo-a-passo da criação de um jogo de quebra-cabeça de imagens em HTML5


Passo-a-passo da criação de um jogo de quebra-cabeça de imagens em HTML5

Como criar um jogo de quebra-cabeça de imagens em HTML5 utilizando canvas, áudio e suporte a fullscreen (tela-cheia).




Demonstração: HTML5 Image Puzzle Game

Código fonte: github.com/edse/puzzle

Tutorial estará disponível em breve.

Tocando vídeos do YouTube em um canvas HTML5 com Javascript


Tocando vídeos do YouTube em um canvas HTML5 com Javascript

Como tocar vídeos do YouTube na tag canvas do HTML5?

Este post estará disponível em breve. Fique ligado!

Como baixar arquivos de vídeos do YouTube com Javascript


Como baixar arquivos de vídeos do YouTube com Javascript

É possível baixar arquivos de vídeo do YouTube via Javascript?

Sim! É possível! E sem precisar de nenhum tipo de script rodando no lado do servidor e também sem nenhum tipo de plugin como Flash e Java Applet instalado no lado do cliente.





Você só precisará do jQuery. Nada mais além disso.

Passo-a-passo: Baixando arquivos de vídeos do YouTube via Javascript

  • Parte 1: Mostrar um input para o usuário entrar com a URL do vídeo do YouTube que ele deseja baixar e validar a URL inserida via expressão regular. 
  var url = $('#url').val();  
  var regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;  
  var match = url.match(regExp);  
  if(match){  
   $('#download-btn').fadeOut('fast');  
   $('#loading').fadeIn('slow');  
   setTimeout("getVideo('"+match[1]+"')",2000);  
  }  
  else{  
   alert('Invalid URL!');  
   $('#url').val("");  
   $('#url').focus();  
  }  

  • Parte 2: Fazer uma requisição via ajax para extrair toda a informação do vídeo do YouTube
    • Faça uma requisição Ajax para o endereço http://www.youtube.com/get_video_info?video_id=XXX (troque o XXX pelo o ID do vídeo)

       $.ajax({  
        url: "http://www.youtube.com/get_video_info?video_id="+id,  
        dataType: "text"  
       }).done(function(data) {
        ...  


  • Parte 3: Preparar a informação recebida para ser interpretada. Para isso precisamos fazer 3 coisas:
    • a) Trocar todas as ocorrências do caractere "\" por "%20"

       data = (data+'').replace(/\+/g, '%20');  
      
    • b) Trocar todas as ocorrências da string "url%3D" para "\n\r<break>"

       data = data.replace(/url%3D/g, '\n\r\n\r<break>');  
      
    • c) Trocar todas as ocorrências da string "sig%3D" to "signature%3D"

       data = data.replace(/sig%3D/g, 'signature%3D');  
      


  • Parte 4: Pegar as URLs de todos os arquivos disponíveis para esse vídeo
  var urls = data.split('<break>');   
  for(var u = 0; u < urls.length; u++){   
  var result = {};   
  ...   
  }   

  • Parte 5: Preparar cada URL para ser interpretada
    • a) Decodificar a URL

       decodeURIComponent((urls[u]+'')  
      
    • b) Trocar todas as ocorrências do caracter "\" por "%20"

       url = url.replace(/\+/g, '%20');  
      
    • c) Dar um "Unescape" do resultado duas vezes

       url = unescape(unescape(url));  
      
    • d) Trocar todas as ocorrências da string '="' para '%3D%22'

       url = url.replace(/="/g, '%3D%22');  
      
    • e) Trocar todas as ocorrências do caracter '"' para "%22"

       url = url.replace(/"/g, '%22');  

  • Parte 6: Retornar uma lista com um link para o download de todos os arquivos de vídeo disponíveis para esse vídeo no YouTube.
    • a) Você precisa extrair todas as variáveis presentes em cada uma das URLs

       var vars = [], hash;  
       var hashes = d.slice(d.indexOf('?') + 1).split('&');  
       for(var i = 0; i < hashes.length; i++){  
        hash = hashes[i].split('=');  
        vars.push(hash[0]);  
        vars[hash[0]] = unescape(hash[1]);  
       }  
      
    • b) Pegue o tipo do vídeo e os codecs através dos parâmetros das URLs

       if(vars['type']!=undefined){  
        result.type = vars['type'];  
        if(vars['type'].indexOf("codecs")>0){  
         var cs = vars['type'].split(';+codecs="');  
         result.type = cs[0];  
         result.codecs = cs[1].replace('"','').replace('+',' ');  
        }  
       }  
      
    • c) Pegue a qualidade do vídeo através dos parâmetros das URLs

       //quality  
       if(vars['quality']!=undefined){  
        result.quality = vars['quality'];  
        if(vars['quality'].indexOf(",")>0){  
         var cs = vars['quality'].split(',');  
         result.quality = cs[0];  
        }  
       }  

É isso! Agora você tem toda a informação necessária armazenada no objeto "result".

Segue o código fonte completo:

 /* Author: Emerson Estrella */  
 $('#again').click(function() {  
  $('#hero2').fadeOut('fast');$('#hero1').fadeIn('slow');  
 });  
 $('#form').submit(function() {  
  var url = $('#url').val();  
  var regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;  
  var match = url.match(regExp);  
  if(match){  
   $('#download-btn').fadeOut('fast');  
   $('#loading').fadeIn('slow');  
   setTimeout("getVideo('"+match[1]+"')",2000);  
  }  
  else{  
   alert('Invalid URL!');  
   $('#url').val("");  
   $('#url').focus();  
  }  
  return false;  
 });  
 function getVideo(youtube_video_id){  
  var id = "b4VsluhWVh8";  
  id = youtube_video_id;  
  $.ajax({  
   url: "http://www.youtube.com/get_video_info?video_id="+id,  
   dataType: "text"  
  }).done(function(data) {  
   var results = [];  
   var r = 0;  
   data = (data+'').replace(/\+/g, '%20');  
   data = data.replace(/url%3D/g, '\n\r\n\r<break>');  
   data = data.replace(/sig%3D/g, 'signature%3D');  
   var urls = data.split('<break>');  
   for(var u = 0; u < urls.length; u++){  
    var result = {};  
    var d = unescape(unescape(decodeURIComponent((urls[u]+'').replace(/\+/g, '%20'))));  
    d = d.replace(/="/g, '%3D%22');  
    d = d.replace(/"/g, '%22');  
    var url = d;  
    //console.log(d);  
    //console.log(d.length);  
    if(d.length > 1500){  
     aux = d.split('&has_cc');  
     d = aux[0];  
    }  
    var vars = [], hash;  
    var hashes = d.slice(d.indexOf('?') + 1).split('&');  
    for(var i = 0; i < hashes.length; i++){  
     hash = hashes[i].split('=');  
     vars.push(hash[0]);  
     vars[hash[0]] = unescape(hash[1]);  
    }  
    if(vars['type']!=undefined){  
     result.type = vars['type'];  
     if(vars['type'].indexOf("codecs")>0){  
      var cs = vars['type'].split(';+codecs="');  
      result.type = cs[0];  
      result.codecs = cs[1].replace('"','').replace('+',' ');  
     }  
    }  
    //quality  
    if(vars['quality']!=undefined){  
     result.quality = vars['quality'];  
     if(vars['quality'].indexOf(",")>0){  
      var cs = vars['quality'].split(',');  
      result.quality = cs[0];  
     }  
    }  
    if(result.type && result.quality){  
     result.url = url;  
     results[r] = result;  
     r++;  
    }  
   }  
   //console.log(results);  
   //print results  
   var html = '';  
   html += '<h4 class="alert-heading" style="margin-top: 25px;">All video files found for your request</h4>';  
   html += '<a id="again" style="margin-top: 25px;" class="btn btn-small btn-danger" href="#main" onclick="$(\'#hero2\').fadeOut(\'fast\');$(\'#hero1\').fadeIn(\'slow\');"><i class="icon-repeat icon-white"></i> Make Another Request</a>';  
   html += '<table class="table table-striped musica" style="background: rgba(255,255,255,0.7); margin-top:25px;"><thead><tr><th>Quality</th><th>Format</th><th>Codecs</th><th style="text-align: right;"></th></tr></thead><tbody>';  
   $.each(results, function(index, value) {  
    html += '\n\r<tr>';  
    html += '<td>'+value.quality+'</td>';  
    html += '<td>'+value.type+'</td>';  
    if(value.codecs!=undefined)  
     html += '<td>'+value.codecs+'</td>';  
    else  
     html += '<td>N/A</td>';  
    html += '<td><a class="btn btn-success pull-left" href="'+value.url+'" style="margin-right: 15px;"><i class="icon-download-alt icon-white"></i> Download this video format file</a></td>';  
    html += '</tr>\n\r';  
   });  
   html += '</tbody></table><a style="margin-top: 10px; margin-bottom: 25px;" class="btn btn-small btn-danger" href="#main" onclick="$(\'#hero2\').fadeOut(\'fast\');$(\'#hero1\').fadeIn(\'slow\');"><i class="icon-repeat icon-white"></i> Make Another Request</a>';  
   $('#vid').html(html);  
   $('#vid').fadeIn('slow');  
   $('#loading').hide();  
   $('#hero1').hide();  
   $('#hero2').fadeIn('slow');  
   $('#download-btn').show();  
  });  
 }  





Fique ligado! Nos próximos posts explicarei como baixar arquivos de vídeos do YouTube via script PHP rodando no servidor.

Como tocar vídeos usando a tag canvas



Como tocar vídeos usando a tag canvas

Tutorial passo-a-passo para tocar um vídeo utilizando a tag canvas



Primeiramente você precisará de um arquivo de vídeo. Na verdade, precisaremos de dois. Um no formato OGG (para Chrome e Firefox) e o outro em MP4 (para o Safari).

Para converter vídeos em diferentes formatos você pode utilizar alguns websites como: www.online-convert.com ou www.mediaconverter.org.

Assim que você tiver os arquivos de vídeos, o próximo passo é criar uma simples página HTML com uma tag canvas e com uma tag video. Siga o exemplo abaixo:

 <!DOCTYPE html>  
 <head>  
 <title>Playing YouTube video on HTML5 canvas</title>  
 </head>  
 <body>  
  <video id="video" autoplay="true" loop="true">  
   <source src="./video/BigBuckBunny_640x360.ogv" type="video/ogg" />  
   <source src="./video/BigBuckBunny_640x360.mp4" type="video/mp4" />  
  </video>  
  <canvas id="canvas"></canvas>  
 </body>  
 </html>  

Agora você pode testar os vídeos, utilizando a tag video, nos diferentes browsers para ver se está tudo correto.

O próximo passo é adicionar um CSS e esconder a tag de vídeo dentro de uma div invisível. Segue o código:

 <!DOCTYPE html>  
 <head>  
 <title>Playing YouTube video on HTML5 canvas</title>  
 </head>  
 <body>  
  <video id="video" autoplay="true" loop="true">  
   <source src="./video/BigBuckBunny_640x360.ogv" type="video/ogg" />  
   <source src="./video/BigBuckBunny_640x360.mp4" type="video/mp4" />  
  </video>  
  <canvas id="canvas"></canvas>  
 </body>  
 </html>  

Como iremos tocar o vídeo na tag canvas, precisaremos esconder a tag video, porém continuaremos a utilizar-lá para reprodução do áudio.

Agora a única parte que falta é o javascript para fazer o render do vídeo na tag canvas. Para fazer isso precisaremos extrair uma imagem do vídeo e mostra-lá no canvas. E se repetirmos esse processo inúmeras vezes durante um intervalo de X em X milisegundos... TA-DA!!! Teremos o vídeo sendo reproduzido no canvas

Aqui está o código fonte completo:

 <!DOCTYPE html>  
 <head>  
 <title>Playing YouTube video on HTML5 canvas</title>  
 <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width" />  
 <style type="text/css">  
  html, body {  
   width: 100%;  
   height: 100%;  
   padding: 0px;  
   margin: 0px;  
  }  
  #canvas {  
   padding: 0px;  
   margin: 0px;  
   top:0;  
   left:0;  
   z-index: 30;  
   position: absolute;  
   width: 100%;  
   height: 100%;  
  }  
 </style>  
 </head>  
 <body>  
  <div style="display: none;">  
   <video id="video" autoplay="true" loop="true">  
    <source src="./video/BigBuckBunny_640x360.ogv" type="video/ogg" />  
    <source src="./video/BigBuckBunny_640x360.mp4" type="video/mp4" />  
   </video>  
  </div>  
  <canvas id="canvas"></canvas>  
  <script>  
  document.addEventListener('DOMContentLoaded', function(){  
   var v = document.getElementById('video');  
   var canvas = document.getElementById('canvas');  
   var context = canvas.getContext('2d');  
   //var cw = Math.floor(canvas.clientWidth / 100);  
   //var ch = Math.floor(canvas.clientHeight / 100);  
   var cw = Math.floor(canvas.clientWidth);  
   var ch = Math.floor(canvas.clientHeight);  
   canvas.width = cw;  
   canvas.height = ch;  
   v.addEventListener('play', function(){  
    draw(this,context,cw,ch);  
   },false);  
  },false);  
  function draw(v,c,w,h) {  
   if(v.paused || v.ended) return false;  
   c.drawImage(v,0,0,w,h);  
   setTimeout(draw,20,v,c,w,h);  
  }  
  </script>  
 </body>  
 </html>  

Se você quiser utilizar a mesma técnica para tocar um vídeo do YouTube, veja esse tutorial: Playing YouTube videos on HTML5 canvas with Javascript.

Se você quiser baixar vídeos do YouTube via Javascript, veja este: Download YouTube video files with Javascript

Nos próximos posts irei mostrar como criar um simple quebra-cabeça em HTML5. Fique ligado!