16 – Como hacer una blob animado en HTML - Parte I

Posted on Sep 14, 2021 – - by Franco
Cover del post

En Twitter encontré el siguiente curso de John Otander & Laurie Barth: Compilers for Humans

CompilersForHumans.com

Me gustó bastante la animación del Hero, así que decidí replicarla con un pequeño cambio, usando puntos en vez de una superficie continua.

Aquí el resultado:

Yo creo que quedó bastante bien. Veamos como hacerla.

Plan de juego

Este tutorial va a ser algo largo, así que será divido en 4 partes.

Consistirá en 4 partes.

  • Parte I: Aprenderemos a utilizar el API de HTML Canvas para dibujar formas primitivas.
  • Parte II: Haremos un pequeño anillo 3D proyectado en 2 dimensiones.
  • Parte III: Haremos una Esfera completa y le añadiremos rotación en los tres ejes.
  • Parte IV: Distorsionaremos la esfera para hacerla parecer un blob.
  • Parte V: Le agregaremos interacciones con el mouse.
  • Parte VI: Le agregaremos controles interactivos para ‘jugar’ con los parametros de nuestra esfera.

Conocimientos previos necesarios

  • Saber instalar Visual Studio Code
  • Seguir indicaciones
  • No tener miedo al código

Recomendados

  • Alguna noción de programación
  • Algo de matemáticas (sumas, restas y multiplicaciones va perfecto).

Nota importante: Vamos a hacer todo este proceso a ’la manera dificil’. Vamos a usar Canvas y un poco de matemáticas (descuida, no vamos a dejar tarea).

Logicamente, hoy en día tenemos bibliotecas para manipular objetos en 3D en el browser de manera muy sencilla como three.js, así que si no te quieres hacerte problemas con las matemáticas podemos usar eso en su lugar.

De todas maneras, estoy convencido que las técnicas básicas y lógica que encontrarás en esta serie de tutoriales te servirá para expandir tu conocimiento en gráficos por computadora. Al terminar, podrás hacer tus propias figuras e incluso modificarlo a tu antojo, y sin ninguna dependencia.

Preparando el campo

Este es el código básico, no lo explicaremos a detalle en este tutorial pero si te dire que es mejor usar un editor como VSCode para editarlo. En una carpeta conocida (como el escritorio) crea un archivo index.html. A continuación, ábrelo en VSCode y escribe el siguiente pedazo de código.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<html lang="en">
	<head>
		<meta charset="UTF-8">
  		<meta http-equiv="X-UA-Compatible" content="IE=edge">
  		<meta name="viewport" content="width=device-width, initial-scale=1.0">
  		<title>Sphere</title>
		<style>
			/* ESTILOS */
		</style>
	</head>
	<body>
		<h1> Sphere.  </h1>
		<h2> <span id="x"> X </span> WeMake.  </h2>
		<canvas id="canvas"></canvas>
	<script>
		// Aquí irá el código de la esfera
	</script>
	</body>
</html>

Como dibujar en un canvas

Primero un poco de teoría, el canvas (o lienzo) en HTML5 es una superficie rectangular que tiene como origen la esquina superior izquierda en el punto (x,y) => (0, 0). En un canvas, podemos dibujar algunas formas 3 primitivas: rectangulos, lineas y arcos. Estas formas tienen a su vez dos colores, el color de relleno y el color del borde, fillStyle y strokeStyle respectivamente.

Canvas

El canvas se pinta secuencialmente, es decir cada figura se pinta una encima de otra como si estuvieramos dibujando en un lienzo. Así que la ultima figura dibujada tapa las figuras anteriores.

Esa es toda la teoría que necesitamos por ahora.

Pongamos la teoría en práctica: Dibujemos un rectangulo rojo, un circulo azul y una linea negra.

Dentro del tag <script> de nuestro código base, coloca lo siguiente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<script>
	// Aquí irá el código de la esfera

	// 0. Setup
   const canvas = document.getElementById('canvas')
   const ctx = canvas.getContext('2d')
   const w = canvas.width = 720 // Ancho: esto puede variarse al tamaño que quieran
   const h = canvas.height = 720 // Alto: esto puede variarse al tamaño que quieran

	// 1. Pintamos un rectangulo
	ctx.fillStyle = 'red' 		// cambiamos el color de relleno a Rojo
	ctx.fillRect(0, 0, w, h); 	//  Pintamos un rectangulo con inicio en 0, 0 y de dimensiones de W y H

	// 2. Pintamos una linea
	ctx.strokeStyle = "black"; // indicamos el color
	ctx.moveTo(w/2, h/2); 		// movemos el cursor a la mitad del canvas
	ctx.lineTo(10, 10); 			// Dibujamos una linea hacia las coordenadas 10,10
	ctx.stroke(); 					// Pedimos que canvas pinte las lineas que hemos dibujado.
	// 3. Pintamos un circulo.
	ctx.fillStyle = 'blue';		// cambiamos el color de relleno a azul
	ctx.beginPath()				// 
	ctx.arc(w/2,  					// coordenada en X
			  h/2, 					// coordenada en Y
			  10, 					// radio del arco
			  0,	 					// angulo de Inicio
			  2 * Math.PI,			// angulo de fin
			  true)  				// Antihorario/Horario
	ctx.fill() 						// Pintamos las figuras cerradas que tenemos pendientes
</script>

Este nuevo código está comentado pero vamos igual linea por linea.

  1. Primero, declaramos unas variables, canvas que usaremos para manipular su tamaño y obtener el contexto. ctx que lo obtenemos de canvas con el método getContext. El ctx o contexto lo vamos a usar para hacer todos los dibujos. Finalmente, w y h son el ancho y alto del canvas respectivamente, y lo modificamos para que sea un cuadrado de 720px por 720px.

  2. Luego en el bloque 1. pintamos un rectángulo. Definimos el color de relleno del contexto red. Luego, pintamos el rectángulo con la función fillRect(x,y,w,h). Los parametros de la funcion indican el punto de inicio, el ancho y alto del rectangulo.

  3. En el bloque 2. pintamos una línea. Primero, cambiamos el color de linea a black. Movemos nuestro pincel a la mitad del rectangulo del canvas con moveTo y luego trazamos una linea hacia la coordenada (10,10) con lineTo

  4. Por ultimo, en el bloque 3 pintamos un circulo, que en canvas API es un arco que da una vuelta de 360 grados. Para hacerlo, usamos la funcion arc(x, y, r, anguloInicio, anguloFin, antiHorario) cuyo parametros explicamos a continuación.

x: centro horizontal del arco
y: centro vertical del arco
r: radio del arco
anguloInicio: angulo de Inicio radianes.
anguloFin: ángulo de Fin en radianes
antihorario: True (verdadero, en este caso como es un circulo completo, no importa mucho)

Nota: Usamos Math.PI * 2 que equivale a 360 grados en radianes.

El resultado de esta primera parte lo detallamos a continuación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<html lang="en">
	<head>
		<meta charset="UTF-8">
  		<meta http-equiv="X-UA-Compatible" content="IE=edge">
  		<meta name="viewport" content="width=device-width, initial-scale=1.0">
  		<title>Sphere</title>
		<style>
			/* ESTILOS */
		</style>
	</head>
	<body>
		<h1> Sphere.  </h1>
		<h2> <span id="x"> X </span> WeMake.  </h2>
		<canvas id="canvas"></canvas>
	<script>
	// Aquí irá el código de la esfera

	// 0. Setup
   const canvas = document.getElementById('canvas')
   const ctx = canvas.getContext('2d')
   const w = canvas.width = 720 // Ancho: esto puede variarse al tamaño que quieran
   const h = canvas.height = 720 // Alto: esto puede variarse al tamaño que quieran

	// 1. Pintamos un rectangulo
	ctx.fillStyle = 'red' 		// cambiamos el color de relleno a Rojo
	ctx.fillRect(0, 0, w, h); 	//  Pintamos un rectangulo con inicio en 0, 0 y de dimensiones de W y H

	// 2. Pintamos una linea
	ctx.strokeStyle = "black"; // indicamos el color
	ctx.moveTo(w/2, h/2); 		// movemos el cursor a la mitad del canvas
	ctx.lineTo(10, 10); 			// Dibujamos una linea hacia las coordenadas 10,10
	ctx.stroke(); 					// Pedimos que canvas pinte las lineas que hemos dibujado.
	// 3. Pintamos un circulo.
	ctx.fillStyle = 'blue';		// cambiamos el color de relleno a azul
	ctx.beginPath()				// 
	ctx.arc(w/2,  					// coordenada en X
			  h/2, 					// coordenada en Y
			  10, 					// radio del arco
			  0,	 					// angulo de Inicio
			  2 * Math.PI,			// angulo de fin
			  true)  				// Antihorario/Horario
	ctx.fill() 						// Pintamos las figuras cerradas que tenemos pendientes
</script>
	</body>
</html>

Y este deberia ser el resultado cuando abrimos el archivo index.html en nuestro browser favorito (Chrome, Firefox, Safari)

Resultado parte 1

No es muy impresionante de por sí, pero les recomiendo que jueguen con esta API para que tengan un buen conocimiento de esta.

Les recomiendo la guia de Mozilla para expandir su conocimiento en esta poderosa API.

Muchas gracias por leer la primera parte, a continuación:

  • Parte II: Haremos un pequeño anillo 3D proyectado en 2 dimensiones. (Próximamente)