Crea con Chrome

Llevando los ladrillos LEGO® a la Web multidispositivo

Build with Chrome, un experimento divertido para usuarios de Chrome para computadoras de escritorio que se lanzó originalmente en Australia, se volvió a lanzar en 2014 con disponibilidad global, vínculos con LA PELÍCULA DE LEGO®™ y compatibilidad recién agregada para dispositivos móviles. En este artículo, compartiremos algunos aprendizajes del proyecto, en especial en relación con el cambio de la experiencia solo para computadoras de escritorio a una solución multipantalla que admite entradas táctiles y del mouse.

Historia de Build with Chrome

La primera versión de Build with Chrome se lanzó en Australia en 2012. Queríamos demostrar el poder de la Web de una manera completamente nueva y llevar Chrome a un público completamente nuevo.

El sitio tenía dos partes principales: el modo "Build", en el que los usuarios podían crear con ladrillos LEGO, y el modo "Explore", para explorar las creaciones en una versión de Google Maps con temática de LEGO.

La interacción en 3D fue esencial para brindarles a los usuarios la mejor experiencia de construcción de LEGO. En 2012, WebGL solo estaba disponible para el público en navegadores para computadoras, por lo que Build se segmentó como una experiencia solo para computadoras. Explorar usaba Google Maps para mostrar las creaciones, pero cuando se acercaba lo suficiente, cambiaba a una implementación de WebGL del mapa que mostraba las creaciones en 3D, y seguía usando Google Maps como textura de la placa base. Queríamos crear un entorno en el que los fanáticos de LEGO de todas las edades pudieran expresar su creatividad de forma intuitiva y sencilla, y explorar las creaciones de los demás.

En 2013, decidimos expandir Build with Chrome a nuevas tecnologías web. Entre esas tecnologías, se encontraba WebGL en Chrome para Android, que, por supuesto, permitiría que Build with Chrome evolucionara a una experiencia para dispositivos móviles. Para comenzar, primero desarrollamos prototipos táctiles antes de cuestionar el hardware de la "herramienta de compilación" para comprender el comportamiento de los gestos y la capacidad de respuesta táctil que podríamos enfrentar a través de un navegador en comparación con una aplicación para dispositivos móviles.

Un frontend responsivo

Necesitábamos admitir dispositivos con entrada táctil y del mouse. Sin embargo, usar la misma IU en pantallas táctiles pequeñas resultó ser una solución subóptima debido a las limitaciones de espacio.

En Build, hay mucha interactividad: acercar y alejar, cambiar los colores de los ladrillos y, por supuesto, seleccionar, rotar y colocar ladrillos. Es una herramienta en la que los usuarios suelen pasar mucho tiempo, por lo que es importante que tengan acceso rápido a todo lo que usan con frecuencia y que se sientan cómodos interactuando con ella.

Cuando diseñes una aplicación táctil altamente interactiva, descubrirás que la pantalla se siente pequeña rápidamente y que los dedos del usuario tienden a cubrir gran parte de la pantalla mientras interactúan. Esto fue evidente para nosotros cuando trabajamos con el compilador. Cuando diseñes, debes tener en cuenta el tamaño físico de la pantalla en lugar de los píxeles de los gráficos. Es importante minimizar la cantidad de botones y controles para obtener la mayor cantidad posible de espacio en pantalla dedicado al contenido real.

Nuestro objetivo era que Build se sintiera natural en dispositivos táctiles, no solo agregando entradas táctiles a la implementación original para computadoras de escritorio, sino que se sintiera como si realmente estuviera diseñada para la función táctil. Terminamos con dos variaciones de la IU, una para computadoras de escritorio y tablets con pantallas grandes y otra para dispositivos móviles con pantallas más pequeñas. Cuando sea posible, es mejor usar una sola implementación y tener una transición fluida entre los modos. En nuestro caso, determinamos que había una diferencia tan significativa en la experiencia entre estos dos modos que decidimos basarnos en un punto de inflexión específico. Las dos versiones tienen muchas funciones en común, y tratamos de hacer la mayor parte de las tareas con una sola implementación de código, pero algunos aspectos de la IU funcionan de manera diferente entre ambas.

Usamos los datos del usuario-agente para detectar dispositivos móviles y, luego, verificamos el tamaño de la vista para decidir si se debe usar la IU para dispositivos móviles de pantalla pequeña. Es un poco difícil elegir un punto de interrupción para lo que debe ser una "pantalla grande", ya que es difícil obtener un valor confiable del tamaño físico de la pantalla. Afortunadamente, en nuestro caso, no importa si mostramos la IU de pantalla pequeña en un dispositivo táctil con una pantalla grande, ya que la herramienta seguirá funcionando bien, solo que algunos de los botones pueden parecer un poco demasiado grandes. Al final, configuramos el punto de inflexión en 1,000 píxeles. Si cargas el sitio desde una ventana más ancha que 1,000 píxeles (en modo horizontal), obtendrás la versión para pantallas grandes.

Hablemos un poco sobre los dos tamaños de pantalla y las experiencias:

Pantalla grande, con compatibilidad con mouse y táctil

La versión para pantallas grandes se entrega a todas las computadoras de escritorio compatibles con mouse y a los dispositivos táctiles con pantallas grandes (como el Google Nexus 10). Esta versión es similar a la solución original para computadoras de escritorio en cuanto al tipo de controles de navegación disponibles, pero agregamos compatibilidad con la función táctil y algunos gestos. Ajustamos la IU según el tamaño de la ventana, de modo que, cuando un usuario cambia el tamaño de la ventana, es posible que se quite o cambie el tamaño de parte de la IU. Para ello, usamos las consultas de medios de CSS.

Ejemplo: Cuando la altura disponible es inferior a 730 píxeles, se oculta el control deslizante de zoom en el modo Explorar:

@media only screen and (max-height: 730px) {
    .zoom-slider {
        display: none;
    }
}

Pantalla pequeña, solo compatibilidad táctil

Esta versión se entrega a dispositivos móviles y tablets pequeñas (dispositivos de destino Nexus 4 y Nexus 7). Esta versión requiere compatibilidad con la función de varios toques.

En los dispositivos con pantallas pequeñas, debemos darle al contenido el mayor espacio posible, por lo que hicimos algunos ajustes para maximizar el espacio, principalmente, quitando de la vista los elementos que se usan con poca frecuencia:

  • El selector de bloques de compilación se minimiza en un selector de color durante la compilación.
  • Reemplazamos los controles de zoom y orientación por gestos multitáctiles.
  • La función de pantalla completa de Chrome también es útil para obtener más espacio en pantalla.
Compila en una pantalla grande
Compila en una pantalla grande. El selector de bloques siempre está visible y hay un par de controles en el lado derecho.
Cómo compilar en una pantalla pequeña
Compila en una pantalla pequeña. El selector de ladrillos se minimiza y se quitaron algunos botones.

Rendimiento y compatibilidad de WebGL

Los dispositivos táctiles modernos tienen GPUs bastante potentes, pero aún están lejos de sus contrapartes para computadoras de escritorio, por lo que sabíamos que tendríamos algunos desafíos con el rendimiento, en especial en el modo Explorar en 3D, en el que debemos renderizar muchas creaciones al mismo tiempo.

En términos de creatividad, queríamos agregar un par de tipos nuevos de ladrillos con formas complejas y hasta transparencia, características que suelen ser muy pesadas para la GPU. Sin embargo, tuvimos que mantener la retrocompatibilidad y seguir admitiendo las creaciones de la primera versión, por lo que no pudimos establecer restricciones nuevas, como reducir significativamente la cantidad total de ladrillos en las creaciones.

En la primera versión de Build, teníamos un límite máximo de bloques que se podían usar en una creación. Había un “medidor de ladrillos” que indicaba cuántos quedaban. En la nueva implementación, algunos de los nuevos ladrillos afectaban al medidor de ladrillos más que los ladrillos estándar, lo que reducía ligeramente la cantidad máxima total de ladrillos. Esta era una forma de incluir nuevos elementos sin dejar de mantener un rendimiento decente.

En el modo Explorar en 3D, suceden muchas cosas al mismo tiempo, como la carga de texturas de la placa base, la carga de creaciones, la animación y la renderización de creaciones, etcétera. Esto requiere mucho de la GPU y la CPU, por lo que realizamos muchas generaciones de perfiles de fotogramas en DevTools de Chrome para optimizar estas partes tanto como fuera posible. En los dispositivos móviles, decidimos acercarnos un poco más a las creaciones para no tener que renderizar tantas creaciones al mismo tiempo.

Algunos dispositivos nos obligaron a volver a revisar y simplificar algunos de los sombreadores de WebGL, pero siempre encontramos una forma de resolverlo y seguir adelante.

Compatibilidad con dispositivos que no son WebGL

Queríamos que el sitio fuera algo utilizable incluso si el dispositivo del visitante no admitía WebGL. A veces, hay formas de representar la 3D de forma simplificada con una solución de lienzo o funciones de CSS3D. Lamentablemente, no encontramos una solución lo suficientemente buena para replicar las funciones de Build and Explore 3D sin usar WebGL.

Para mantener la coherencia, el estilo visual de las creaciones debe ser el mismo en todas las plataformas. Podríamos haber intentado una solución en 2.5D, pero esto habría hecho que las creaciones se vieran diferentes de alguna manera. También tuvimos que considerar cómo asegurarnos de que las creaciones creadas con la primera versión de Build with Chrome se vieran igual y se ejecutaran tan bien en la nueva versión del sitio como en la primera.

Los dispositivos que no son compatibles con WebGL aún pueden acceder al modo de exploración 2D, aunque no se pueden crear nuevas creaciones ni explorar en 3D. De esta manera, los usuarios pueden tener una idea de la profundidad del proyecto y de lo que podrían crear con esta herramienta si tuvieran un dispositivo compatible con WebGL. Es posible que el sitio no sea tan valioso para los usuarios que no admiten WebGL, pero al menos debería actuar como un anticipo y hacerlos participar en la prueba.

A veces, no es posible mantener versiones de resguardo para las soluciones de WebGL. Existen muchos motivos posibles, como el rendimiento, el estilo visual, los costos de desarrollo y mantenimiento, etcétera. Sin embargo, si decides no implementar un resguardo, al menos debes ocuparte de los visitantes que no tienen habilitado WebGL, explicarles por qué no pueden acceder al sitio por completo y darles instrucciones para que puedan resolver el problema con un navegador compatible con WebGL.

Administración de recursos

En 2013, Google presentó una nueva versión de Google Maps con los cambios más significativos en la IU desde su lanzamiento. Por lo tanto, decidimos rediseñar Build with Chrome para que se adapte a la nueva IU de Google Maps y, al hacerlo, tuvimos en cuenta otros factores. El nuevo diseño es relativamente plano, con colores sólidos y formas simples. Esto nos permitió usar CSS puro en muchos de los elementos de la IU, lo que minimizó el uso de imágenes.

En Explorar, debemos cargar muchas imágenes: miniaturas para las creaciones, texturas de mapas para las placas base y, por último, las creaciones en 3D reales. Nos aseguramos de que no haya fugas de memoria cuando cargamos imágenes nuevas constantemente.

Las creaciones en 3D se almacenan en un formato de archivo personalizado empaquetado como una imagen PNG. Mantener los datos de las creaciones en 3D almacenados como una imagen nos permitió pasar los datos directamente a los sombreadores que renderizan las creaciones.

En el caso de todas las imágenes generadas por el usuario, el diseño nos permitió usar los mismos tamaños de imagen en todas las plataformas, lo que minimizó el uso de almacenamiento y ancho de banda.

Cómo administrar la orientación de la pantalla

Es fácil olvidar cuánto cambia la relación de aspecto de la pantalla cuando se pasa del modo vertical al horizontal o viceversa. Debes tener esto en cuenta desde el principio cuando realices la adaptación para dispositivos móviles.

En un sitio web tradicional con desplazamiento habilitado, puedes aplicar reglas de CSS para obtener un sitio responsivo que reordene el contenido y los menús. Siempre que puedas usar la función de desplazamiento, esto es bastante fácil de controlar.

También usamos este método con Build, pero teníamos algunas limitaciones para resolver el diseño, ya que necesitábamos que el contenido estuviera visible en todo momento y, al mismo tiempo, tener acceso rápido a varios controles y botones. Para los sitios de contenido puro, como los sitios de noticias, un diseño fluido tiene mucho sentido, pero para una app de juegos como la nuestra, fue un problema. Fue un desafío encontrar un diseño que funcionara en orientación horizontal y vertical sin dejar de tener una buena descripción general del contenido y una forma cómoda de interactuar. Al final, decidimos mantener la compilación solo en modo horizontal y le pedimos al usuario que rote el dispositivo.

Explorar fue mucho más fácil de resolver en ambas orientaciones. Solo tuvimos que ajustar el nivel de zoom de la vista en 3D según la orientación para obtener una experiencia coherente.

La mayor parte del diseño del contenido está controlado por CSS, pero algunos elementos relacionados con la orientación debían implementarse en JavaScript. Descubrimos que no había una buena solución multidispositivo para usar window.orientation para identificar la orientación, por lo que, al final, solo comparamos window.innerWidth y window.innerHeight para identificar la orientación del dispositivo.

if( window.innerWidth > window.innerHeight ){
  //landscape
} else {
  //portrait
}

Cómo agregar compatibilidad táctil

Agregar compatibilidad con el control táctil al contenido web es bastante sencillo. La interactividad básica, como el evento de clic, funciona de la misma manera en computadoras de escritorio y dispositivos compatibles con la función táctil, pero cuando se trata de interacciones más avanzadas, también debes controlar los eventos táctiles: touchstart, touchmove y touchend. En este artículo, se abordan los aspectos básicos para usar estos eventos. Internet Explorer no admite eventos táctiles, sino que usa eventos de puntero (pointerdown, pointermove, pointerup). Los eventos del puntero se enviaron al W3C para su estandarización, pero por ahora solo se implementan en Internet Explorer.

En el modo Explorar en 3D, queríamos la misma navegación que la implementación estándar de Google Maps: usar un dedo para desplazar el mapa y pellizcar con dos dedos para acercar o alejar. Como las creaciones son en 3D, también agregamos el gesto de rotación con dos dedos. Por lo general, esto requerirá el uso de eventos táctiles.

Una práctica recomendada es evitar el procesamiento intensivo, como actualizar o renderizar el 3D en los controladores de eventos. En su lugar, almacena la entrada táctil en una variable y reacciona a la entrada en el bucle de renderización de requestAnimationFrame. Esto también facilita tener una implementación del mouse al mismo tiempo, ya que solo debes almacenar los valores del mouse correspondientes en las mismas variables.

Primero, inicializa un objeto para almacenar la entrada y agrega el objeto de escucha del evento touchstart. En cada controlador de eventos, llamamos a event.preventDefault(). Esto evita que el navegador siga procesando el evento táctil, lo que podría causar un comportamiento inesperado, como el desplazamiento o el escalamiento de toda la página.

var input = {dragStartX:0, dragStartY:0, dragX:0, dragY:0, dragDX:0, dragDY:0, dragging:false};
plateContainer.addEventListener('touchstart', onTouchStart);

function onTouchStart(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
    //start listening to all needed touchevents to implement the dragging
    document.addEventListener('touchmove', onTouchMove);
    document.addEventListener('touchend', onTouchEnd);
    document.addEventListener('touchcancel', onTouchEnd);
  }
}

function onTouchMove(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragging(event.touches[0].clientX, event.touches[0].clientY);
  }
}

function onTouchEnd(event) {
  event.preventDefault();
  if( event.touches.length === 0){
    handleDragStop();
    //remove all eventlisteners but touchstart to minimize number of eventlisteners
    document.removeEventListener('touchmove', onTouchMove);
    document.removeEventListener('touchend', onTouchEnd);
    //also listen to touchcancel event to avoid unexpected behavior when switching tabs and some other situations
    document.removeEventListener('touchcancel', onTouchEnd);
  }
}

No estamos realizando el almacenamiento real de la entrada en los controladores de eventos, sino en controladores separados: handleDragStart, handleDragging y handleDragStop. Esto se debe a que queremos poder llamar a estos también desde los controladores de eventos del mouse. Ten en cuenta que, aunque es poco probable, el usuario puede usar la pantalla táctil y el mouse al mismo tiempo. En lugar de manejar ese caso directamente, nos aseguramos de que no haya problemas.

function handleDragStart(x ,y ){
  input.dragging = true;
  input.dragStartX = input.dragX = x;
  input.dragStartY = input.dragY = y;
}

function handleDragging(x ,y ){
  if(input.dragging) {
    input.dragDX = x - input.dragX;
    input.dragDY = y - input.dragY;
    input.dragX = x;
    input.dragY = y;
  }
}

function handleDragStop(){
  if(input.dragging) {
    input.dragging = false;
    input.dragDX = 0;
    input.dragDY = 0;
  }
}

Cuando se realizan animaciones basadas en el evento touchmove, a menudo es útil almacenar el movimiento delta desde el último evento. Por ejemplo, lo usamos como parámetro para la velocidad de la cámara cuando se mueve por todas las placas base en Explorar, ya que no arrastras las placas base, sino que mueves la cámara.

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );

  //execute animation based on input.dragDX, input.dragDY, input.dragX or input.dragY
 /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX=0;
  input.dragDY=0;
}

Ejemplo incorporado: Arrastrar un objeto con eventos táctiles Implementación similar a la que se realiza cuando se arrastra el mapa 3D de Explorar en Build with Chrome: http://cdpn.io/qDxvo

Gestos multitáctiles

Existen varios frameworks o bibliotecas, como Hammer o QuoJS, que pueden simplificar la administración de los gestos multitáctiles, pero si quieres combinar varios gestos y obtener el control total, a veces es mejor hacerlo desde cero.

Para administrar los gestos de pellizcar y rotar, almacenamos la distancia y el ángulo entre dos dedos cuando se coloca el segundo dedo en la pantalla:

//variables representing the actual scale/rotation of the object we are affecting
var currentScale = 1;
var currentRotation = 0;

function onTouchStart(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
  }else if( event.touches.length === 2 ){
    handleGestureStart(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY );
  }
}

function handleGestureStart(x1, y1, x2, y2){
  input.isGesture = true;
  //calculate distance and angle between fingers
  var dx = x2 - x1;
  var dy = y2 - y1;
  input.touchStartDistance=Math.sqrt(dx*dx+dy*dy);
  input.touchStartAngle=Math.atan2(dy,dx);
  //we also store the current scale and rotation of the actual object we are affecting. This is needed to support incremental rotation/scaling. We can't assume that an object is always the same scale when gesture starts.
  input.startScale=currentScale;
  input.startAngle=currentRotation;
}

En el evento touchmove, medimos de forma continua la distancia y el ángulo entre esos dos dedos. Luego, se usa la diferencia entre la distancia inicial y la distancia actual para establecer la escala, y la diferencia entre el ángulo inicial y el ángulo actual para establecer el ángulo.

function onTouchMove(event) {
  event.preventDefault();
  if( event.touches.length  === 1){
    handleDragging(event.touches[0].clientX, event.touches[0].clientY);
  }else if( event.touches.length === 2 ){
    handleGesture(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY );
  }
}

function handleGesture(x1, y1, x2, y2){
  if(input.isGesture){
    //calculate distance and angle between fingers
    var dx = x2 - x1;
    var dy = y2 - y1;
    var touchDistance = Math.sqrt(dx*dx+dy*dy);
    var touchAngle = Math.atan2(dy,dx);
    //calculate the difference between current touch values and the start values
    var scalePixelChange = touchDistance - input.touchStartDistance;
    var angleChange = touchAngle - input.touchStartAngle;
    //calculate how much this should affect the actual object
    currentScale = input.startScale + scalePixelChange*0.01;
    currentRotation = input.startAngle+(angleChange*180/Math.PI);
    //upper and lower limit of scaling
    if(currentScale<0.5) currentScale = 0.5;
    if(currentScale>3) currentScale = 3;
  }
}

Podrías usar el cambio de distancia entre cada evento touchmove de manera similar al ejemplo con el arrastre, pero ese enfoque suele ser más útil cuando deseas un movimiento continuo.

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );
  //execute transform based on currentScale and currentRotation
  /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX=0;
  input.dragDY=0;
}

Si lo deseas, también puedes habilitar el arrastre del objeto mientras haces los gestos de pellizcar y rotar. En ese caso, usarías el punto central entre los dos dedos como entrada para el controlador de arrastre.

Ejemplo incorporado: Rotación y escalamiento de un objeto en 2D. Similar a la forma en que se implementa el mapa en Explorar: http://cdpn.io/izloq

Compatibilidad con mouse y táctil en el mismo hardware

Actualmente, existen varias laptops, como la Chromebook Pixel, que admiten entradas táctiles y de mouse. Esto puede causar algunos comportamientos inesperados si no tienes cuidado.

Un aspecto importante es que no solo debes detectar la compatibilidad con la función táctil y, luego, ignorar la entrada del mouse, sino que debes admitir ambas al mismo tiempo.

Si no usas event.preventDefault() en tus controladores de eventos táctiles, también se activarán algunos eventos de mouse emulados para que la mayoría de los sitios optimizados para no usar la función táctil sigan funcionando. A modo de ejemplo, para un solo toque en la pantalla, estos eventos pueden activarse en una secuencia rápida y en este orden:

  1. touchstart
  2. touchmove
  3. touchend
  4. desplazar el mouse sobre un anuncios
  5. mousemove
  6. mousedown
  7. mouseup
  8. Hacer clic

Si tienes interacciones un poco más complejas, estos eventos del mouse pueden causar un comportamiento inesperado y desordenar tu implementación. A menudo, es mejor usar event.preventDefault() en los controladores de eventos táctiles y administrar la entrada del mouse en controladores de eventos separados. Debes tener en cuenta que usar event.preventDefault() en los controladores de eventos táctiles también evitará algunos comportamientos predeterminados, como el desplazamiento y el evento de clic.

"En Build with Chrome, no queríamos que se produjera el zoom cuando alguien presionaba dos veces el sitio, aunque eso es estándar en la mayoría de los navegadores. Por lo tanto, usamos la metaetiqueta de viewport para indicarle al navegador que no realice el zoom cuando un usuario presione dos veces. Esto también quita la demora de clic de 300 ms, lo que mejora la capacidad de respuesta del sitio. (La demora del clic sirve para distinguir entre un toque y un doble toque cuando el zoom con doble toque está habilitado).

<meta name="viewport" content="width=device-width,user-scalable=no">

Recuerda que, cuando uses esta función, depende de ti que el sitio sea legible en todos los tamaños de pantalla, ya que el usuario no podrá acercar la imagen.

Entrada de mouse, táctil y teclado

En el modo Explorar en 3D, queríamos que hubiera tres formas de navegar por el mapa: con el mouse (arrastrar), con la función táctil (arrastrar, pellizcar para acercar y rotar) y con el teclado (navegar con las teclas de flecha). Todos estos métodos de navegación funcionan de manera ligeramente diferente, pero usamos el mismo enfoque en todos ellos: configurar variables en controladores de eventos y actuar en función de eso en el bucle requestAnimationFrame. El bucle requestAnimationFrame no tiene que saber qué método se usa para navegar.

A modo de ejemplo, podríamos establecer el movimiento del mapa (dragDX y dragDY) con los tres métodos de entrada. Esta es la implementación del teclado:

document.addEventListener('keydown', onKeyDown );
document.addEventListener('keyup', onKeyUp );

function onKeyDown( event ) {
  input.keyCodes[ "k" + event.keyCode ] = true;
  input.shiftKey = event.shiftKey;
}

function onKeyUp( event ) {
  input.keyCodes[ "k" + event.keyCode ] = false;
  input.shiftKey = event.shiftKey;
}

//this needs to be called every frame before animation is executed
function handleKeyInput(){
  if(input.keyCodes.k37){
    input.dragDX = -5; //37 arrow left
  } else if(input.keyCodes.k39){
    input.dragDX = 5; //39 arrow right
  }
  if(input.keyCodes.k38){
    input.dragDY = -5; //38 arrow up
  } else if(input.keyCodes.k40){
    input.dragDY = 5; //40 arrow down
  }
}

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );
  //because keydown events are not fired every frame we need to process the keyboard state first
  handleKeyInput();
  //implement animations based on what is stored in input
   /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX = 0;
  input.dragDY = 0;
}

Ejemplo incorporado: Usa el mouse, el panel táctil y el teclado para navegar: http://cdpn.io/catlf

Resumen

Adaptar Build with Chrome para admitir dispositivos táctiles con muchos tamaños de pantalla diferentes fue una experiencia de aprendizaje. El equipo no tenía mucha experiencia en este nivel de interactividad en dispositivos táctiles y aprendimos mucho en el proceso.

El mayor desafío resultó ser cómo resolver la experiencia del usuario y el diseño. Los desafíos técnicos fueron administrar muchos tamaños de pantalla, eventos táctiles y problemas de rendimiento.

Aunque hubo algunos desafíos con los sombreadores de WebGL en dispositivos táctiles, esto funcionó casi mejor de lo esperado. Los dispositivos son cada vez más potentes y las implementaciones de WebGL mejoran rápidamente. Creemos que usaremos WebGL en dispositivos mucho más en el futuro cercano.

Ahora, si aún no lo hiciste, crea algo increíble.