Criação da experiência interativa do Vyclone com HTML5

Criação da experiência interativa do Vyclone com HTML5

A Web se torna mais estimulante e produtiva para os clientes à medida que os desenvolvedores revelam todo o potencial do HTML5. Nesta postagem do blog, nosso convidado Anton Molleda da Plain Concepts fala sobre a sua experiência e seus aprendizados durante o desenvolvimento da Vcylone, uma experiência de edição de vídeo social criada no HTML5. Molleda falará também sobre os muitos novos recursos dos navegadores da última geração, como o Internet Explorer 10. O Vcyclone baseia-se em funcionalidades como eventos de ponteiros, gestos de multitoque, tela acelerada por hardware e CSS3 para fazer com que este site da Web pareça mais com um aplicativo.

— Rob Mauceri, gerente de programas de grupo, Internet Explorer

Olá, pessoal,

Meu nome é Anton Molleda e trabalho para a Plain Concepts. Nestes últimos meses, a equipe do Internet Explorer tem colaborado com a equipe incrível que constitui a inicialização do vídeo social Vyclone que está por vir. Como desenvolvedor da Web, a oportunidade de superar as expectativas explorando as possibilidades da Web é uma das minhas paixões. Felizmente, a sorte estava do meu lado e pude ajudar neste projeto. E hoje, quero compartilhar com vocês algumas descobertas importantes que fizemos durante nosso trabalho para criar um editor de vídeo na Web para o Vyclone, usando apenas o HTML5 e o JavaScript!

O Vyclone é uma plataforma de vídeo social que permite que você ajude a criar, sincronizar e editar várias exibições de um momento compartilhado, sem esforço algum.

Quando o Vyclone é iniciado pela primeira vez, seu principal foco são os dispositivos móveis. Contudo, foi observado logo depois que, embora a experiência de gravação seja ótima em um telefone, a edição do vídeo ficou limitada devido ao tamanho da tela e à capacidade do dispositivo. Graças ao progresso feito nos últimos anos em navegadores modernos, o HTML5 se tornou uma opção viável para criar essa nova ferramenta.

O núcleo do editor da Web do Vyclone é composto por três partes:

A visualização de vídeo: onde uma versão de baixa qualidade do corte criado pelo usuário pode ser assistido (à esquerda).

A grade de vídeos: onde todas as fontes disponíveis são apresentadas ao usuário com exibição de um determinado ponto e hora (à direita).

E a linha do tempo: que indica uma exibição linear de qual fonte está sendo reproduzida durante o vídeo. Uma fonte reproduzida durante um determinado período é chamada de corte (mostrada acima dos controles do player).

Editor da Web do Vyclone

Conforme o usuário reproduz o vídeo e começa a adicionar novos cortes à linha do tempo, a visualização do vídeo é alternada para refletir a nova fonte e a grade de vídeos destaca o arquivo de fonte com bordas triangulares para identificar para o usuário qual vídeo foi selecionado.

Portanto, desenvolvendo isso, encontramos um desafio muito interessante com um grande volume de manipulação de vídeo, o desempenho que estamos recebendo e a experiência do usuário. Vamos falar mais sobre o que fizemos para que isso acontecesse na Web. Então, estamos usando vídeo, tela e requestAnimationFrame (RAF). Há um vídeo em reprodução no plano de fundo e, em cada RAF, escrevemos a fonte ativa em uma tela (na visualização de vídeo) ou calculamos seu novo tamanho e posição na grade de vídeos.

Até agora tudo bem, mas o que acontece quando deixamos o usuário interagir com ele? Por exemplo, o que acontece quando um usuário move a linha do tempo para frente e para trás ou adiciona/remove fontes de vídeo (cortes)? Quando começamos a fazer este protótipo, pensamos que a abordagem padrão seria resolver isso assim que o evento fosse disparado -porque foi assim que aprendemos, não é mesmo?

Mas o que acontece quando esses eventos são disparados dezenas de vezes por segundo ou, até mesmo, centenas de vezes por segundo? E se esses manipuladores precisarem atualizar a interface do usuário? Nós realmente precisamos forçar uma atualização de layout 130 vezes por segundo quando a alteração delta poderia, algumas vezes, ser inferior a um pixel? Isso é que é lentidão de desempenho!

Se a sua máquina tem um i7 com 8 GB de RAM, você pode, provavelmente, obter capacidade de computação para fazer isso. Mas e as pessoas com um simulador de carga mais antigo? Ou um dispositivo ARM? Esses usuários não terão a mesma experiência e verão o tempo de reação do site da Web diminuir muito.

Nossa primeira abordagem foi enfileirar a ação no RAF, mas ocorreram alguns problemas com essa abordagem. Por exemplo, você pode colocar o RAF da mesma função para o mesmo "tique", piorando ainda mais a situação. Para resolvê-lo, nossa primeira abordagem foi a criação de uma variável que indique se a ação já foi enfileirada. Algo como:

 var queued = false; function myAction(){ //your awesome code here queued = false; } function onEvent(evt){ if(!queued){ queued = true; requestAnimationFrame(myAction); } }

Este código não é ruim, mas ainda tem alguns problemas. Se você estiver fazendo algo relacionado a uma posição de evento (mouse ou ponteiro) e um delta, talvez descubra que terá problemas com essa abordagem. A solução que usamos na linha do tempo foi acumular o valor do evento e processá-lo em myAction:

 var deltaX = 0, queued = false; function myAction(){ //your awesome code here uses deltaX deltaX = 0; // we reset the deltaX so it can be incremented  // next time onEvent is executed queued = false; } function onEvent(evt){ if(!queued){ queued = true; deltaX = evt.translationX; // in the case of a pointer, if you are  // using a mouse you will have to do some  // magic with pageX or similar :) requestAnimationFrame(myAction); }else{ deltaX += evt.translationX; } }

Com essa abordagem, você estará praticamente pronto para começar. Continuamos adicionando funcionalidade e, então, descobrimos alguns novos problemas.

Manipulando esses eventos quando apropriado em cada requestAnimationFrame podemos atingir um nível mais alto de capacidade de resposta, sem sacrificar a capacidade de computação. Mas como o requestAnimationFrame executa as funções na ordem, elas são enfileiradas de maneira que, algumas vezes, escrevíamos antes de apagar, ou movimentávamos a linha do tempo quando ainda não era necessário e precisávamos criar muitos códigos importantes para garantir que ele fosse executado na ordem em que queríamos.

Percebemos que esse código não era muito amigável e estávamos perdendo alguns ciclos esperando que outras ações fossem executadas. Portanto, decidimos mudar novamente a manipulação da entrada. Foi nesse momento que passamos a pensar nela como um loop de jogo. Para quem não conhece a arquitetura de jogos (simples), o loop de jogo é basicamente um loop contínuo que continua sendo executado independentemente da interação do usuário e se divide quando eventos e ações diferentes precisam ocorrer. De acordo com o artigo da Wikipédia "Programação de jogos eletrônicos", um loop de jogo simplificado em pseudocódigos poderia ser assim:

 while( user doesn't exit ) check for user input run AI move enemies resolve collisions draw graphics play sounds end while

Era exatamente o que precisávamos. Aproveitando o RAF, criamos uma função de tique que é executada continuamente e, dentro dessa função, decidimos o que precisamos fazer dependendo de entradas anteriores do usuário ou outros fatores.

O tique simplificado para a grade de vídeos é algo como:

 function tick(){ //we clean if we've changed the size of the quadrant if(needsClean){ cleanCanvas(); } // if we have to change the quadrant's frame because we are  // the active one (or the opposite) if(newFrame){ drawFrame(); // we draw just the frame in a separate canvas so it // doesn't need to be calculated all the time, and it  // is still faster than copying from an image } //we draw the new frame if we are playing or seeking if(dirty){ draw(); drawFrameInQuadrant(); } requestAnimationFrame(tick); }

O valor de needsClean, newFrame e dirty são atualizados nos manipuladores do evento (quando o usuário está buscando, reproduzindo vídeos etc.).

Foi essa alternação na maneira com que pensamos nas interações do usuário, passando para uma mecânica de loop de jogos, que permitiu o aumento do desempenho e a simplificação do código no editor.

Importantes lições aprendidas: se você estiver criando algo que exige alta interatividade e recebe muita entrada de usuários, pense em como possivelmente o uso do loop de jogo pode facilitar sua vida! Com certeza facilitou a nossa. E se você ainda não teve a oportunidade de conferir o novo e atraente editor da Web da Vyclone (modéstia à parte), corra! Clique em ‘Remix’ em qualquer vídeo em Vyclone.com e você encontrará nosso editor da Web. Ele funciona tão bem com mouse tanto com toque Eu recomendo muito que você experimente em um Surface Pro!

Aproveite! Se tiver alguma dúvida, escreva seus comentários aqui embaixo!

— Anton Molleda, Plain Concepts