Crea con Chrome

Lleva los ladrillos LEGO® a la Web de múltiples dispositivos

Build with Chrome, un divertido experimento para usuarios de Chrome para computadoras de escritorio que se lanzó originalmente en Australia, se volvió a lanzar en 2014 y se volvió a lanzar en 2014 con disponibilidad global, vínculos con THE LEGO® PELÍCULATM y compatibilidad reciente con los dispositivos móviles. En este artículo compartiremos algunos aprendizajes del proyecto, especialmente en lo que respecta al cambio de la experiencia solo para computadoras de escritorio a una solución multipantalla que admite mouse y entrada táctil.

La historia de Construye con Chrome

La primera versión de Construye con 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 totalmente nuevo.

El sitio tenía dos partes principales: el modo "Construir", en el que los usuarios pueden construir creaciones con ladrillos LEGO, y el modo "Explorar", que permite explorar las creaciones en una versión de Google Maps clasificada con LEGO.

El modo 3D interactivo fue fundamental para que los usuarios vivieran la mejor experiencia de construcción con LEGO. En 2012, WebGL solo estaba disponible públicamente en los navegadores de escritorio, por lo que Build fue pensada como una experiencia solo de escritorio. Explorar usó Google Maps para mostrar las creaciones, pero cuando se acercó lo suficiente, se cambió a una implementación de WebGL del mapa que mostraba las creaciones en 3D, pero que aún utilizaba Google Maps como textura de la placa base. Esperábamos construir un entorno en el que los entusiastas de LEGO de todas las edades pudieran expresar su creatividad de manera intuitiva y fácil, 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 encuentra WebGL en Chrome para Android, que naturalmente permitiría que Build with Chrome se convirtiera en una experiencia móvil. Para empezar, desarrollamos prototipos táctiles antes de cuestionar el hardware de la "Builder Tool" para comprender el comportamiento gestual y la capacidad de respuesta táctil que podemos enfrentar a través de un navegador en comparación con una aplicación móvil.

Un frontend responsivo

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

En Build, hay mucha interactividad: acercarse y alejarse, 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 parece pequeña rápidamente y que los dedos del usuario tienden a cubrir gran parte de ella mientras interactúa. Esto se volvió evidente para nosotros cuando trabajamos con Builder. Realmente debes considerar el tamaño físico de la pantalla en lugar de los píxeles en los gráficos al hacer el diseño. Es importante minimizar la cantidad de botones y controles para obtener el mayor espacio posible en pantalla dedicado al contenido real.

Nuestro objetivo era lograr que Build se sintiera natural en los dispositivos táctiles, no solo agregar entradas táctiles a la implementación original de escritorio, sino que se sintiera como realmente estaba destinado al tacto. 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 modos. En nuestro caso, determinamos que hubo una diferencia tan significativa en la experiencia entre estos dos modos que decidimos basarnos en un punto de interrupción específico. Las dos versiones tienen muchas funciones en común. Intentamos hacer la mayoría de las cosas con una sola implementación de código, pero algunos aspectos de la IU funcionan de manera diferente entre ambas.

Usamos datos de usuario-agente para detectar dispositivos móviles y, luego, verificamos el tamaño del viewport 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 debería ser una "pantalla grande", porque 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 pantalla grande, porque la herramienta seguirá funcionando bien, solo que algunos de los botones pueden parecer demasiado grandes. Al final, estableceremos el punto de interrupción en 1,000 píxeles. Si cargas el sitio desde una ventana de más de 1,000 píxeles (en modo horizontal), obtendrás la versión para pantalla grande.

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

Pantalla grande con mouse y compatibilidad táctil

La versión de pantalla grande se entrega a todas las computadoras de escritorio compatibles con mouse y para dispositivos táctiles con pantallas grandes (como Google Nexus 10). Esta versión es similar a la solución de escritorio original en cuanto a los tipos de controles de navegación disponibles, pero agregamos compatibilidad táctil y algunos gestos. Ajustamos la IU según el tamaño de la ventana, por lo que, cuando un usuario cambia el tamaño de la ventana, puede quitar o cambiar 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, el control del control deslizante de zoom en el modo Explorar está oculto.

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

Pantalla pequeña, solo compatibilidad táctil

Esta versión se publica en dispositivos móviles y tablets pequeñas (dispositivos Nexus 4 y Nexus 7). Esta versión requiere compatibilidad con varios toques.

En los dispositivos de pantalla pequeña, debemos darle al contenido tanto espacio en pantalla como sea posible, por lo que hicimos algunos ajustes para maximizar el espacio, principalmente moviendo los elementos que se usan con poca frecuencia fuera de la vista:

  • El selector de ladrillos de compilación se minimiza en un selector de colores mientras se construye.
  • Reemplazamos los controles de zoom y orientación por gestos multitáctiles.
  • La funcionalidad de pantalla completa de Chrome también es útil para aumentar el espacio en pantalla.
Crea contenido en una pantalla grande
Compila en una pantalla grande. El selector de ladrillos siempre está visible y hay un par de controles a la derecha.
Crea contenido en una pantalla pequeña
Compila en una pantalla pequeña. Se minimizó el selector de ladrillos y se quitaron algunos botones.

Rendimiento y asistencia de WebGL

Los dispositivos táctiles modernos tienen GPU bastante potentes, pero todavía están lejos de las versiones para computadoras de escritorio, así que sabíamos que tendríamos algunos desafíos con el rendimiento, en especial en el modo Explorar 3D, en el que necesitamos renderizar muchas creaciones al mismo tiempo.

Creativamente, queríamos agregar un par de nuevos tipos de ladrillos con formas complejas e incluso transparencias, características que generalmente son muy pesadas en la GPU. Sin embargo, teníamos que ser retrocompatibles y seguir admitiendo creaciones de la primera versión, por lo que no podíamos establecer ninguna restricción nueva, como la reducción significativa de la cantidad de ladrillos en las creaciones.

En la primera versión de Construye con Chrome, teníamos un límite máximo de ladrillos que se podían utilizar en una creación. Había un "medidor de ladrillos" que indicaba cuántos ladrillos quedaban. En la nueva implementación, algunos de los ladrillos nuevos afectaron el medidor de ladrillos más que los ladrillos estándar, lo que redujo ligeramente la cantidad máxima total de ladrillos. Esta era una forma de incluir nuevos ladrillos y sin dejar de mantener un rendimiento aceptable.

En el modo Explorar 3D, suceden muchas cosas al mismo tiempo: cargas de texturas de placas base, cargas de creaciones, animaciones y renderizaciones, etc. Esto requiere mucho de la GPU y la CPU, por lo que hicimos una generación de perfiles de fotogramas en las Herramientas para desarrolladores 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 hicieron revisar y simplificar algunos de los sombreadores de WebGL, pero siempre encontramos una forma de resolverlos y seguir adelante.

Compatibilidad con dispositivos que no son WebGL

Queríamos que el sitio fuera un poco utilizable, incluso si el dispositivo del visitante no era compatible con WebGL. A veces, hay maneras de representar el 3D de forma simplificada con una solución de lienzo o funciones CSS3D. Por desgracia, no encontramos una solución lo suficientemente buena como para replicar funciones de Creación y exploración en 3D sin usar WebGL.

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

Los dispositivos que no sean WebGL aún pueden acceder al modo Explorar en 2D, aunque no puedas crear creaciones nuevas ni explorar en 3D. Por lo tanto, los usuarios aún pueden tener una idea de la profundidad del proyecto y lo que podrían crear con esta herramienta si estuvieran en un dispositivo habilitado con WebGL. Es posible que el sitio no sea tan valioso para los usuarios que no tienen compatibilidad con WebGL, pero debería al menos actuar como un avance y motivar a los usuarios para que lo prueben.

A veces, no es posible conservar versiones de resguardo para las soluciones WebGL. Existen muchos motivos posibles: rendimiento, estilo visual, costos de desarrollo y mantenimiento, entre otros. Sin embargo, cuando decidas no implementar un resguardo, debes al menos atender a los visitantes que no son habilitados para WebGL, explicar por qué no pueden acceder al sitio por completo y darles instrucciones para resolver el problema usando un navegador compatible con WebGL.

Administración de activos

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 adaptara a la nueva IU de Google Maps y, al hacerlo, se incorporaron otros factores al rediseño. El nuevo diseño es relativamente plano, con colores sólidos limpios y formas simples. Esto nos permitió usar CSS puro en muchos de los elementos de la IU, lo que minimiza el uso de imágenes.

En Explorar tenemos que cargar muchas imágenes; imágenes en miniatura para las creaciones, texturas de mapa para las placas base y, por último, creaciones en 3D reales. Tenemos especial cuidado para asegurarnos de que no haya fugas de memoria cuando carguemos imágenes nuevas de manera constante.

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

Para 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 minimiza 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 considerar esto desde el principio cuando te adaptes a los dispositivos móviles.

En un sitio web tradicional que tiene habilitado el desplazamiento, puedes aplicar reglas de CSS para obtener un sitio responsivo que reorganiza el contenido y los menús. Siempre y cuando uses la funcionalidad de desplazamiento, esto es bastante manejable.

También usamos este método con Build, pero teníamos algunas limitaciones en cuanto a cómo podíamos resolver el diseño, porque necesitábamos tener el contenido visible en todo momento y seguir teniendo acceso rápido a varios controles y botones. En el caso de los sitios de contenido puro, como los de noticias, usar un diseño fluido tiene mucho sentido; sin embargo, para una app de juego como la nuestra, resultó muy difícil. Se convirtió en un desafío encontrar un diseño que funcionara tanto en orientación horizontal como vertical mientras mantuviera una buena descripción general del contenido y una forma cómoda de interactuar. Al final, decidimos mantener Build solo en orientación horizontal y le dijimos al usuario que rote su dispositivo.

Explorar fue mucho más fácil de resolver en ambas orientaciones. Solo necesitábamos ajustar el nivel de zoom del 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 y así 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 táctil al contenido web es razonablemente sencillo. La interactividad básica, como el evento de clic, funciona de la misma manera en computadoras de escritorio y dispositivos táctiles, 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 utilizar estos eventos. Internet Explorer no admite eventos táctiles, sino que usa eventos de puntero (pointerdown, punteromov, puntero hacia arriba). Los eventos de puntero se enviaron a W3C para su estandarización, pero, por ahora, solo se implementan en Internet Explorer.

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

Se recomienda 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 la implementación de un mouse al mismo tiempo; simplemente almacenas los valores correspondientes del mouse en las mismas variables.

Comienza por inicializar un objeto para almacenar la entrada y agrega el objeto de escucha de eventos touchstart. En cada controlador de eventos, llamamos a event.preventDefault(). Esto sirve para evitar que el navegador continúe procesando el evento táctil, lo que podría provocar un comportamiento inesperado, como desplazarse o escalar 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 guardando la entrada en los controladores de eventos, sino en controladores separados: handleDragStart, handleDragging y handleDragStop. Esto se debe a que queremos poder llamarlos también desde los controladores de eventos del mouse. Ten en cuenta que, aunque es poco probable, el usuario puede utilizar el modo táctil y el mouse al mismo tiempo. En lugar de tratar ese caso directamente, nos aseguramos de que no salga nada.

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 crean animaciones basadas en touchmove, suele ser útil almacenar también el movimiento delta desde el último evento. Por ejemplo, usamos esto como un parámetro para la velocidad de la cámara cuando nos movemos por todas las placas base en Explorar, ya que no arrastras las placas base, sino que en realidad 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: Arrastra un objeto mediante eventos táctiles. La implementación es similar a la que se obtiene cuando se arrastra el mapa Explorar en 3D en Build with Chrome: http://cdpn.io/qDxvo

Gestos multitáctiles

Hay varios frameworks o bibliotecas, como Hammer o QuoJS, que pueden simplificar la administración de gestos de varios toques, pero si deseas 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 el segundo dedo se coloca 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 continuamente la distancia y el ángulo entre esos dos dedos. A continuación, se usa la diferencia entre la distancia inicial y la distancia actual para configurar la escala, y la diferencia entre el ángulo inicial y el actual se usa 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 potencialmente el cambio de distancia entre cada evento touchmove de una manera similar al ejemplo con 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;
}

También puedes habilitar la arrastre del objeto mientras realizas los gestos de pellizcar y rotar si lo deseas. En ese caso, utilizarías el punto central entre los dos dedos como entrada para el controlador de arrastre.

Ejemplo incorporado: Rotar y escalar un objeto en 2D. Así es como se implementa el mapa en Explorar: http://cdpn.io/izloq

Compatibilidad táctil y mouse en el mismo hardware

En la actualidad, hay varias laptops, como la Chromebook Pixel, que admiten mouse y entrada táctil. Esto puede causar comportamientos inesperados si no tienes cuidado.

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

Si no usas event.preventDefault() en tus controladores de eventos táctiles, también se activarán algunos eventos del mouse emulados para que la mayoría de los sitios optimizados no táctiles sigan funcionando. Por ejemplo, si presionas una vez la pantalla una vez, estos eventos se pueden activar en una secuencia rápida y en el siguiente orden:

  1. inicio táctil
  2. movimiento táctil
  3. punto de contacto
  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 alterar 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 el uso de event.preventDefault() en los controladores de eventos táctiles también evitará ciertos comportamientos predeterminados, como el desplazamiento y el evento de clic.

"En Construye con Chrome, no queríamos que se hiciera zoom cuando alguien tocaba dos veces el sitio, a pesar de que es algo estándar en la mayoría de los navegadores. Así que usamos la metaetiqueta de la vista del puerto para indicarle al navegador que no haga zoom cuando un usuario toca dos veces. Esto también quita la demora en los clics de 300 ms, lo que mejora la capacidad de respuesta del sitio. (La demora al hacer clic sirve para distinguir entre presionar una vez y presionar dos veces cuando el zoom está habilitado).

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

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

Entrada táctil, mouse y teclado

En el modo Explorar 3D, queríamos que hubiera tres formas de navegar por el mapa: mouse (arrastrar), tocar (arrastrar, pellizcar para acercar y rotar) y teclado (navegar con las teclas de flecha). Todos estos métodos de navegación funcionan de forma un poco diferente, pero usamos el mismo enfoque en todos ellos: configuramos variables en controladores de eventos y actuamos de acuerdo con eso en el bucle requestAnimationFrame. El bucle requestAnimationFrame no necesita saber qué método se utiliza para navegar.

A modo de ejemplo, se puede configurar 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 modo táctil y el teclado para navegar: http://cdpn.io/catlf

Resumen

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

El mayor desafío resultó ser cómo resolver el diseño y la experiencia del usuario. Los desafíos técnicos eran la administración de 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 es algo que funcionó casi mejor de lo esperado. Los dispositivos son cada vez más potentes y las implementaciones de WebGL mejoran rápidamente. Creemos que, en los dispositivos, usaremos mucho más WebGL en un futuro cercano.

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