Lopaka Basics 07: animações

Este cavalo foi fotografado em 1887. Agora ele é um GIF, galopando em uma telinha do Arduino: quinze quadros, e eles cabem. Torne ele em tela cheia e um pouco mais suave, e o sketch não cabe mais.
Neste episódio, você vai descobrir como a animação funciona em uma tela pequena e de quanta memória ela precisa. Depois você vai transformar um GIF em código no Lopaka, executar ele em um Arduino UNO simulado e colocar um mês inteiro de fases da lua em um ESP32.
O que você vai construir: um cavalo a galope a partir de um GIF em um OLED de 128×64 com um Arduino UNO, e um mês de fases da lua a partir de um vídeo no mesmo OLED com um ESP32. Do que você precisa: um navegador e a configuração do simulador do episódio 1: um OLED SSD1306 e a biblioteca U8g2. Para o cavalo, usamos o cavalo a galope de Eadweard Muybridge (Animal Locomotion, 1887, domínio público); qualquer GIF curto funciona.
Quadros e taxa de quadros
Uma animação é uma pilha de imagens
Uma animação é uma pilha de imagens estáticas. Mostre elas uma depois da outra, rápido o suficiente, e seu olho para de ver imagens e começa a ver movimento.
Essa velocidade é a taxa de quadros, em quadros por segundo (FPS). A dois quadros por segundo, o cavalo é uma apresentação de slides. A dez, ele galopa.

O loop reproduz ela quadro a quadro
Um microcontrolador reproduz uma animação do mesmo jeito. Cada passagem de loop() desenha o quadro atual, envia ele para a tela, espera um momento e passa para o próximo quadro. Depois do último quadro, ele volta ao primeiro.

Cada quadro custa memória
Um quadro em tela cheia tem 1.024 bytes
O OLED tem 128 por 64 pixels, e cada pixel é um bit: aceso ou apagado. Isso dá 8.192 bits, ou 1.024 bytes para um quadro em tela cheia. Um quadro de qualquer tamanho ocupa largura × altura ÷ 8 bytes.

Um Arduino UNO guarda 23 quadros em tela cheia
Os quadros moram na memória flash, ao lado do seu programa. Um Arduino UNO tem 32 KB de flash, e a biblioteca U8g2 e o sketch já ocupam cerca de 8 KB dela. Isso deixa espaço para 23 quadros em tela cheia. Conferimos com o compilador: com 23 quadros, o sketch usa 99% da flash do UNO, e o 24º quadro torna ele grande demais.

Por que o cavalo cabe e a tela cheia não
O cavalo tem 96 por 64 pixels, então um quadro ocupa 96 × 64 ÷ 8 = 768 bytes. Quinze quadros dão cerca de 11 KB, e o sketch cabe em 62% da flash.

Tela cheia a vinte quadros por segundo precisa de trinta quadros de 1.024 bytes, e o sketch cresce para 121% da flash. O compilador para com "Sketch too big". Mas o GIF tem só quinze desenhos. Para reproduzir ele a vinte quadros por segundo, o sketch mostra cada desenho duas vezes, então metade desses trinta quadros são cópias.

Três jeitos de fazer uma animação caber
- Menos quadros. Mantenha a taxa de quadros do próprio GIF: uma maior só adiciona cópias.
- Quadros menores. Cada linha e coluna que você corta economiza bytes em cada quadro.
- Uma placa maior. Um ESP32 tem 1,25 MB de flash para o seu programa: espaço para cerca de mil quadros em tela cheia.

Etapa 1: importe um GIF
Crie um novo projeto como no episódio 1: + New Project, plataforma U8g2, tamanho de tela 128×64.
A biblioteca de animações
Abra a guia Animações à esquerda. O Lopaka vem com ícones animados prontos, e a estimativa de tamanho fica ao lado dos botões de tamanho e qualidade. Um ícone de 64×64 em qualidade High ocupa cerca de 14 KB; em 32×32 e qualidade Low, fica abaixo de um kilobyte. Escolha um ícone ali quando uma animação pequena é tudo de que você precisa.
Envie seu GIF
Para o seu próprio GIF, clique em Upload no topo do painel e solte o arquivo na caixa de diálogo. Vídeos também funcionam, como você vai ver na etapa 5.
O Lopaka divide o GIF em quadros e abre a caixa de diálogo de importação. Os quadros ficam à esquerda, a pré-visualização no meio, as configurações à direita:
- Dithering: mude ele de Floyd-Steinberg para No dithering. A foto vira uma silhueta branca limpa em vez de uma nuvem de pontos. O dithering ajuda com tons, como no episódio 2; uma silhueta não precisa de nenhum.
- Frames per second: mantenha 10, a velocidade do próprio GIF.
A linha na parte inferior faz a conta da memória para você: 15 quadros de origem, 15 quadros de saída, tamanho do quadro 96×64, cerca de 11,3 KiB. O Lopaka dimensionou o GIF de 300×200 para a altura da tela, 64 pixels, o que torna ele com 96 pixels de largura. Um quadro tem 768 bytes, o número no topo das configurações.

Um erro comum é aumentar a taxa de quadros para deixar o GIF mais suave. A 20 FPS, a caixa de diálogo mostra 15 quadros de origem, mas 30 quadros de saída, e a estimativa dobra para 22,5 KiB: os mesmos quinze desenhos, cada um duas vezes.
Clique em Import.
Etapa 2: o editor de quadros
Os quadros abrem no editor de quadros, com os quinze na linha do tempo na parte inferior.
- Play (o botão de triângulo) confere o loop.
- Com o interruptor Onion ativado, o quadro anterior aparece em cinza, então você consegue ver quanto as pernas se movem de um quadro para o próximo.
As fotos antigas têm números na borda inferior, e a importação transformou eles em marcas brancas. Remova eles de todos os quadros de uma vez: clique no tamanho do quadro ao lado da taxa de quadros (96×64 px), defina Height como 60 e clique em Resize. Os pixels ficam ancorados no canto superior esquerdo, então as quatro linhas inferiores somem em cada quadro, e o contador de memória cai de 11,3 para 10,6 KiB. Se um quadro ainda tiver alguns pontos de um número na borda inferior, vá até ele e apague eles com a borracha.

Clique em Salvar. A animação fica na tela como qualquer outra camada, chamada horse, em X 16 e Y 0: (128 − 96) ÷ 2 = 16 coloca ela no meio.
Etapa 3: o código
Quadros direto no código
Nos interruptores ao lado do código, desmarque Animation helpers. Agora o Lopaka escreve os quadros direto no código, e seu próprio loop() decide quando desenhar eles:
// [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]O que os números significam:
[15][720]: um array de quinze quadros, 720 bytes cada. Uma linha de 96 pixels ocupa 96 ÷ 8 = 12 bytes, e 60 linhas fazem 720. No total, são 10.800 bytes, os 10,6 KiB do editor de quadros.U8X8_PROGMEMmantém os quadros na flash, como com as imagens no episódio 2. Sem ele, um UNO tentaria copiar eles para os 2 KB de RAM dele.drawXBMP(16, 0, 96, 60, ...)desenha o quadro atual na posição e no tamanho da camada.(animation_horse_frame + 1) % 15passa para o próximo quadro.% 15é o resto depois de dividir por 15, então depois do quadro 14 (o décimo quinto, contando do zero) o contador volta para 0.
O resto do sketch
Ao redor do bloco gerado, escreva o resto do sketch. Você pode digitar ele no painel de código do Lopaka: linhas acima de // [BEGIN lopaka generated] e abaixo de // [END lopaka generated] são suas, elas ficam no projeto quando você muda o design, e Copiar leva elas junto.
#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 passagem de loop() é um quadro: limpar, desenhar, enviar, esperar. Este é o loop do começo do artigo.
![O painel de código no Lopaka com o include e o display acima do bloco gerado, o array de quadros animation_horse_frames[15][720] U8X8_PROGMEM, a função de desenho e setup e loop com delay(56) abaixo; Animation helpers está desmarcado](/pages/blog/assets/2026-11-03/animation-code.png)
Por que o delay é de 56 milissegundos
Enviar um quadro completo para o OLED por I2C leva cerca de 44 milissegundos no UNO simulado. Adicione um delay de 56 milissegundos, e cada quadro leva 100 milissegundos: dez quadros por segundo, a velocidade do GIF. Em uma placa real, o tempo para enviar um quadro depende da velocidade do I2C; se o cavalo correr rápido ou devagar demais, mude o delay.
Clique em Copiar.
Etapa 4: execute ele em um Arduino UNO
Abra seu projeto do simulador do episódio 1: um Arduino UNO e um OLED SSD1306 ligados a GND, 5V, A5 (SCL) e A4 (SDA), com a biblioteca U8g2. Cole o código em sketch.ino e pressione Play.
O cavalo galopa. Compilado para um UNO, o 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.Isso é 59% da flash, abaixo dos 62% de antes de cortarmos as quatro linhas. Como no episódio 1, a maior parte da RAM é o buffer de quadro de 1.024 bytes.
Etapa 5: um vídeo em um ESP32
Importe o vídeo
O Lopaka também importa vídeo (MP4, MOV e WebM). Usamos um clipe do NASA Scientific Visualization Studio que mostra um mês inteiro de fases da lua em dez segundos.
Crie outro projeto U8g2 em 128×64, abra Animações e clique em Upload. A caixa de diálogo de importação para um vídeo faz a conta enquanto você muda as configurações:
- Na taxa de 30 quadros por segundo do vídeo, dez segundos fazem 300 quadros em 64×64: 150 KiB.
- Uma lua lenta fica boa a 12 quadros por segundo: digite
12, e vira 120 quadros, 60 KiB. - Ative Invert result. O Lopaka acende as partes escuras de uma imagem, e é por isso que o cavalo escuro em um fundo claro saiu branco. A lua é o contrário, brilhante em um céu escuro, então inverta o resultado: agora a lua acende e o céu fica escuro.
Mantenha o dithering Floyd-Steinberg desta vez: os pontos desenham o sombreamento da superfície da lua.

Clique em Import e depois em Salvar no editor de quadros. O Lopaka centraliza a animação de 64×64 na tela, em X 32. Desmarque Animation helpers de novo, e o código recebe animation_moon_frames[120][512] e a linha animation_moon_frame = (animation_moon_frame + 1) % 120;.
60 KB: o dobro do UNO, menos de 5% de um ESP32
Em 64 por 64 pixels, cada quadro tem 64 × 64 ÷ 8 = 512 bytes, então 120 quadros ocupam 61.440 bytes, 60 KB. Isso é cerca do dobro da flash inteira do UNO.

Um ESP32 tem 1.310.720 bytes de flash para o programa, e o mesmo clipe ocupa 4,7% dela.
Execute ele no ESP32
Use o mesmo sketch com o código da lua no lugar dele e mude o delay para delay(32);. O ESP32 envia um quadro em cerca de 51 milissegundos no simulador, então cada quadro leva cerca de 83 milissegundos: 12 quadros por segundo.
No simulador, crie um projeto ESP32, adicione o OLED SSD1306 e a biblioteca U8g2 e ligue o display aos pinos I2C do ESP32: GND ao GND, VCC ao 3V3, SCL ao GPIO 22 e SDA ao GPIO 21. Cole o sketch e pressione Play. O compilador informa 352.240 bytes, 26% da flash, e a lua cresce e encolhe por um mês inteiro.

Recapitulação
- Uma animação é uma pilha de quadros, mostrada rápido o suficiente para parecer movimento. Cada passagem de
loop()limpa, desenha um quadro, envia ele e espera. - Cada quadro custa largura × altura ÷ 8 bytes de flash. Um quadro em tela cheia neste OLED tem um kilobyte, e um UNO guarda cerca de vinte deles.
- Para fazer um GIF caber, use menos quadros, quadros menores ou uma placa maior.
Próximo episódio: Touch UI with LVGL. Telas sensíveis ao toque, com botões e controles deslizantes, como em um celular. Leia o episódio 8 ou assista no YouTube.
Pronto para testar? Abra o Lopaka e dê vida ao seu próprio GIF.