Lopaka Basics 07: animaciones

Este caballo fue fotografiado en 1887. Ahora es un GIF, galopando en una pantalla diminuta de Arduino: quince fotogramas, y caben. Hazlo a pantalla completa y un poco más suave, y el sketch ya no cabe en absoluto.
En este episodio descubrirás cómo funciona la animación en una pantalla pequeña y cuánta memoria necesita. Después convertirás un GIF en código en Lopaka, lo ejecutarás en un Arduino UNO simulado y pondrás todo un mes de fases lunares en un ESP32.
Lo que vas a crear: un caballo al galope a partir de un GIF en un OLED de 128×64 con un Arduino UNO, y un mes de fases lunares a partir de un video en el mismo OLED con un ESP32. Lo que necesitas: un navegador y la configuración de simulador del episodio 1: un OLED SSD1306 y la biblioteca U8g2. Para el caballo usamos el caballo al galope de Eadweard Muybridge (Animal Locomotion, 1887, dominio público); cualquier GIF corto funciona.
Fotogramas y velocidad de fotogramas
Una animación es una pila de imágenes
Una animación es una pila de imágenes fijas. Muéstralas una tras otra, lo bastante rápido, y tu ojo deja de ver imágenes y empieza a ver movimiento.
Esa velocidad es la velocidad de fotogramas, en fotogramas por segundo (FPS). A dos fotogramas por segundo el caballo es una presentación de diapositivas. A diez, galopa.

El loop lo reproduce fotograma a fotograma
Un microcontrolador reproduce una animación igual. Cada pasada de loop() dibuja el fotograma actual, lo envía a la pantalla, espera un momento y pasa al fotograma siguiente. Tras el último fotograma salta de vuelta al primero.

Cada fotograma cuesta memoria
Un fotograma a pantalla completa son 1.024 bytes
El OLED tiene 128 por 64 píxeles y cada píxel es un bit: encendido o apagado. Eso son 8.192 bits, o 1.024 bytes para un fotograma a pantalla completa. Un fotograma de cualquier tamaño ocupa width × height ÷ 8 bytes.

Un Arduino UNO guarda 23 fotogramas a pantalla completa
Los fotogramas viven en memoria flash, junto a tu programa. Un Arduino UNO tiene 32 KB de flash y la biblioteca U8g2 y el sketch ya ocupan unos 8 KB de ella. Eso deja sitio para 23 fotogramas a pantalla completa. Lo comprobamos con el compilador: con 23 fotogramas el sketch usa el 99% de la flash del UNO y el fotograma 24 hace que sea demasiado grande.

Por qué el caballo cabe y la pantalla completa no
El caballo mide 96 por 64 píxeles, así que un fotograma ocupa 96 × 64 ÷ 8 = 768 bytes. Quince fotogramas suman unos 11 KB y el sketch cabe en el 62% de la flash.

La pantalla completa a veinte fotogramas por segundo necesita treinta fotogramas de 1.024 bytes y el sketch crece al 121% de la flash. El compilador se detiene con «Sketch too big». Pero el GIF solo tiene quince dibujos. Para reproducirlo a veinte fotogramas por segundo, el sketch muestra cada dibujo dos veces, así que la mitad de esos treinta fotogramas son copias.

Tres formas de hacer que una animación quepa
- Menos fotogramas. Mantén la velocidad de fotogramas propia del GIF: una higher solo añade copias.
- Fotogramas más pequeños. Cada fila y columna que recortas ahorra bytes en cada fotograma.
- Una placa más grande. Un ESP32 tiene 1,25 MB de flash para tu programa: sitio para unos mil fotogramas a pantalla completa.

Paso 1: importa un GIF
Crea un proyecto nuevo como en el episodio 1: + New Project, plataforma U8g2, tamaño de pantalla 128×64.
La biblioteca de animaciones
Abre la pestaña Animations a la izquierda. Lopaka viene con íconos animados listos para usar y la estimación de tamaño está junto a los botones de tamaño y calidad. Un ícono de 64×64 en calidad High ocupa unos 14 KB; a 32×32 y calidad Low es menos de un kilobyte. Elige un ícono ahí cuando todo lo que necesitas es una animación pequeña.
Sube tu GIF
Para tu propio GIF, haz clic en Upload en la parte superior del panel y suelta el archivo en el diálogo. Los videos también funcionan, como verás en el paso 5.
Lopaka divide el GIF en fotogramas y abre el diálogo de importación. Los fotogramas están a la izquierda, la vista previa en el centro, los ajustes a la derecha:
- Dithering: cámbialo de Floyd-Steinberg a No dithering. La foto se convierte en una silueta blanca limpia en lugar de una nube de puntos. El tramado ayuda con los tonos, como en el episodio 2; una silueta no necesita ninguno.
- Frames per second: mantén 10, la velocidad propia del GIF.
La fila inferior hace las cuentas de memoria por ti: 15 fotogramas de origen, 15 fotogramas de salida, tamaño de fotograma 96×64, unos 11,3 KiB. Lopaka escaló el GIF de 300×200 a la altura de la pantalla, 64 píxeles, lo que lo hace de 96 píxeles de ancho. Un fotograma son 768 bytes, el número en la parte superior de los ajustes.

Un error común es subir la velocidad de fotogramas para hacer el GIF más suave. A 20 FPS el diálogo muestra 15 fotogramas de origen pero 30 fotogramas de salida y la estimación se duplica a 22,5 KiB: los mismos quince dibujos, cada uno dos veces.
Haz clic en Import.
Paso 2: el editor de fotogramas
Los fotogramas se abren en el editor de fotogramas, con los quince en la línea de tiempo inferior.
- Play (el botón de triángulo) comprueba el bucle.
- Con el interruptor Onion activado, el fotograma anterior se ve a través en gris, para que puedas ver cuánto se mueven las patas de un fotograma al siguiente.
Las fotos antiguas tienen números en el borde inferior y la importación los convirtió en marcas blancas. Elimínalos de todos los fotogramas a la vez: haz clic en el tamaño de fotograma junto a la velocidad (96×64 px), pon Height en 60 y haz clic en Resize. Los píxeles quedan anclados a la esquina superior izquierda, así que las cuatro filas inferiores desaparecen en cada fotograma y el contador de memoria cae de 11,3 a 10,6 KiB. Si un fotograma aún tiene unos puntos de un número en el borde inferior, ve a él y bórralos con la goma.

Haz clic en Save. La animación se sitúa en la pantalla como cualquier otra capa, llamada horse, en X 16 e Y 0: (128 − 96) ÷ 2 = 16 la pone en el centro.
Paso 3: el código
Fotogramas directos al código
En los interruptores junto al código, desmarca Animation helpers. Ahora Lopaka escribe los fotogramas directos en el código y tu propio loop() decide cuándo dibujarlos:
// [BEGIN lopaka generated]
static const unsigned char animation_horse_frames[15][720] U8X8_PROGMEM = {
{0x00,0x00,0x00, /* ... */ 0x00,0x00}, // frame 1: 720 bytes, shortened here
// ... 13 more frames ...
{0x00,0x00,0x00, /* ... */ 0xff,0xff} // frame 15
};
static int animation_horse_frame = 0;
void drawScreen_1(void) {
u8g2.setFontMode(1);
u8g2.setBitmapMode(1);
// horse
u8g2.drawXBMP(16, 0, 96, 60, animation_horse_frames[animation_horse_frame]);
animation_horse_frame = (animation_horse_frame + 1) % 15;
}
// [END lopaka generated]Qué significan los números:
[15][720]: un array de quince fotogramas, 720 bytes cada uno. Una fila de 96 píxeles ocupa 96 ÷ 8 = 12 bytes y 60 filas hacen 720. En total son 10.800 bytes, los 10,6 KiB del editor de fotogramas.U8X8_PROGMEMmantiene los fotogramas en flash, como con las imágenes del episodio 2. Sin él, un UNO intentaría copiarlos a sus 2 KB de RAM.drawXBMP(16, 0, 96, 60, ...)dibuja el fotograma actual en la posición y el tamaño de la capa.(animation_horse_frame + 1) % 15pasa al fotograma siguiente.% 15es el resto tras dividir entre 15, así que tras el fotograma 14 (el decimoquinto, contando desde cero) el contador salta de vuelta a 0.
El resto del sketch
Alrededor del bloque generado, escribe el resto del sketch. Puedes escribirlo en el panel de código de Lopaka: las líneas sobre // [BEGIN lopaka generated] y bajo // [END lopaka generated] son tuyas, permanecen en el proyecto cuando cambias el diseño y Copy las lleva consigo.
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
// Paste the Lopaka code here
void setup() {
u8g2.begin();
}
void loop() {
u8g2.clearBuffer();
drawScreen_1();
u8g2.sendBuffer();
delay(56);
}Cada pasada de loop() es un fotograma: limpiar, dibujar, enviar, esperar. Este es el bucle del principio del artículo.
![El panel de código en Lopaka con el include y la pantalla sobre el bloque generado, el array de fotogramas animation_horse_frames[15][720] U8X8_PROGMEM, la función de dibujo, y setup y loop con delay(56) debajo; Animation helpers está desmarcado](/pages/blog/assets/2026-11-03/animation-code.png)
Por qué el retardo es de 56 milisegundos
Enviar un fotograma completo al OLED por I2C lleva unos 44 milisegundos en el UNO simulado. Añade un retardo de 56 milisegundos y cada fotograma lleva 100 milisegundos: diez fotogramas por segundo, la velocidad del GIF. En una placa real el tiempo para enviar un fotograma depende de la velocidad I2C; si el caballo va demasiado rápido o demasiado lento, cambia el retardo.
Haz clic en Copy.
Paso 4: ejecútalo en un Arduino UNO
Abre tu proyecto de simulador del episodio 1: un Arduino UNO y un OLED SSD1306 cableado a GND, 5V, A5 (SCL) y A4 (SDA), con la biblioteca U8g2. Pega el código en sketch.ino y pulsa Play.
El caballo galopa. Compilado para un UNO, el sketch informa:
Sketch uses 19324 bytes (59%) of program storage space. Maximum is 32256 bytes.
Global variables use 1558 bytes (76%) of dynamic memory, leaving 490 bytes for local variables. Maximum is 2048 bytes.Eso es el 59% de la flash, por debajo del 62% antes de recortar las cuatro filas. Como en el episodio 1, la mayor parte de la RAM es el búfer de fotogramas de 1.024 bytes.
Paso 5: un video en un ESP32
Importa el video
Lopaka también importa video (MP4, MOV y WebM). Usamos un clip del NASA Scientific Visualization Studio que muestra todo un mes de fases lunares en diez segundos.
Crea otro proyecto U8g2 a 128×64, abre Animations y haz clic en Upload. El diálogo de importación para un video hace las cuentas mientras cambias los ajustes:
- A los 30 fotogramas por segundo del video, diez segundos hacen 300 fotogramas a 64×64: 150 KiB.
- Una luna lenta se ve bien a 12 fotogramas por segundo: escribe
12y se convierten en 120 fotogramas, 60 KiB. - Activa Invert result. Lopaka enciende las partes oscuras de una imagen, por lo que el caballo oscuro sobre un fondo claro salió blanco. La luna es lo contrario, brillante sobre un cielo oscuro, así que invierte el resultado: ahora la luna se enciende y el cielo queda oscuro.
Esta vez mantén el tramado Floyd-Steinberg: los puntos dibujan el sombreado de la superficie de la luna.

Haz clic en Import y después en Save en el editor de fotogramas. Lopaka centra la animación de 64×64 en la pantalla, en X 32. Desmarca Animation helpers otra vez y el código obtiene animation_moon_frames[120][512] y la línea animation_moon_frame = (animation_moon_frame + 1) % 120;.
60 KB: el doble del UNO, menos del 5% de un ESP32
A 64 por 64 píxeles cada fotograma son 64 × 64 ÷ 8 = 512 bytes, así que 120 fotogramas ocupan 61.440 bytes, 60 KB. Eso es aproximadamente el doble de toda la flash del UNO.

Un ESP32 tiene 1.310.720 bytes de flash para el programa y el mismo clip ocupa el 4,7% de ella.
Ejecútalo en el ESP32
Usa el mismo sketch con el código de la luna en su sitio y cambia el retardo a delay(32);. El ESP32 envía un fotograma en unos 51 milisegundos en el simulador, así que cada fotograma lleva unos 83 milisegundos: 12 fotogramas por segundo.
En el simulador, crea un proyecto ESP32, añade el OLED SSD1306 y la biblioteca U8g2, y cablea la pantalla a los pines I2C del ESP32: GND a GND, VCC a 3V3, SCL a GPIO 22 y SDA a GPIO 21. Pega el sketch y pulsa Play. El compilador informa 352.240 bytes, el 26% de la flash, y la luna crece y mengua durante todo un mes.

Resumen
- Una animación es una pila de fotogramas, mostrados lo bastante rápido para parecer movimiento. Cada pasada de
loop()limpia, dibuja un fotograma, lo envía y espera. - Cada fotograma cuesta width × height ÷ 8 bytes de flash. Un fotograma a pantalla completa en este OLED es un kilobyte y un UNO guarda unos veinte.
- Para hacer que un GIF quepa, usa menos fotogramas, fotogramas más pequeños o una placa más grande.
Próximo episodio: Touch UI with LVGL. Pantallas táctiles, con botones y sliders, como en un teléfono. Lee el episodio 8 o míralo en YouTube.
¿Listo para probar? Abre Lopaka y da vida a tu propio GIF.