← voltar à cena

Álbum Copa do Mundo 2026

Caderno de 994 figurinhas que precisa funcionar na banca de troca, onde não há rede: grava offline, sincroniza depois e lê o código do cromo por foto.

No ar · app privado de uso pessoal · junho a julho de 2026

O problema

O álbum da Panini da Copa de 2026 tem 994 figurinhas. Quem coleciona sabe de cor umas trinta e erra o resto — e erra caro, porque comprar repetida é dinheiro fora. O controle costuma viver numa lista de papel ou numa nota do celular, que serve enquanto ninguém pergunta “você tem a KSA 14?” no meio de uma roda de troca.

O detalhe que decide a arquitetura inteira é geográfico: os lugares onde o álbum é usado — a banca, o portão da escola, a mesa de troca na casa de alguém — são exatamente os lugares de pior sinal. Um app que precisa de rede para registrar uma figurinha é pior que o papel que ele substitui, porque o papel nunca falha em silêncio.

Somam-se duas restrições que vieram do dono: um único usuário e custo zero de operação.

Offline não é modo degradado — é o modo normal

A regra que organiza todo o resto: a rede nunca fica no caminho entre o toque e o número na tela. Marcar uma figurinha grava primeiro no banco do próprio navegador e devolve a interface atualizada na hora. O servidor descobre depois.

Caminho de uma marcação, do toque ao servidor Tocar num cromo grava imediatamente no IndexedDB do aparelho e a tela já mostra o número novo. A mesma escrita entra numa fila local do que ainda falta subir. Quando há rede, a fila envia um POST para a rota de sincronização e o servidor grava no banco D1, onde vence sempre o registro mais recente; só uma resposta 200 remove o item da fila. Se a sessão de login tiver expirado, o gate responde com um redirecionamento em vez de 200 — o app trata isso como falha, mantém a fila intacta e pede login de novo, em vez de dar a escrita como salva. o caminho de uma marcação toque no cromo +1 repetida IndexedDB grava na hora tela atualizada fila local o que falta subir POST /api/sync quando há rede 200 → sai da fila D1 no servidor vence o mais recente 302 do gate sessão expirou resposta ≠ 200 não é sucesso: a fila fica intacta e o app pede login de novo.
O ramo da esquerda é o que separa sincronização de perda de dados. O login fica num gate de rede antes da aplicação, e um gate responde a sessão vencida com redirecionamento — nunca com erro. Cliente que confia no "deu certo" apaga a fila e some com as marcações feitas offline.

Entre dois aparelhos vence o carimbo de tempo mais recente por figurinha. Para uma pessoa com celular e desktop isso é exato, e custa uma coluna em vez de uma biblioteca de resolução de conflito. O catálogo — 48 seleções e as figurinhas especiais — nunca muda em uso: é semeado no servidor uma vez e copiado para o aparelho na primeira carga, então a única coisa que trafega depois é a posse.

Tela inicial do app: barra de progresso geral marcando 994 de 994 figurinhas, uma linha separada para as especiais, uma frase de ritmo com dias restantes até a data-limite, campo de busca e o começo da grade de seleções com a porcentagem de cada uma.
A abertura responde a primeira pergunta antes de qualquer navegação: quanto falta, no total e por seleção. A linha de ritmo compara o passo atual com o passo necessário até a data em que o álbum precisa estar fechado.

Ler a figurinha por foto

O gesto mais caro do app era digitar. Ninguém quer teclar KSA 14 com uma pilha de figurinhas na mão — e o código está impresso no verso de cada uma. Então a câmera passou a ser um caminho de entrada.

O ponto que faz diferença é onde a leitura acontece: o motor de reconhecimento roda no próprio aparelho, servido pelo mesmo domínio do app. Modelo e runtime somam cerca de 26 MB, buscados só quando alguém abre a tela de leitura e guardados pelo service worker a partir daí. Nenhuma foto sai do dispositivo, nenhuma chamada vai para serviço de terceiro, e a leitura continua funcionando offline — o que era o requisito desde o começo, já que ler figurinha é justamente o que se faz na banca.

Foto tirada à mão do verso de uma figurinha Panini, com os dizeres de licença e um número de série impresso na lateral; abaixo, a resposta do app propondo o cromo KSA14, Saleh Abu Alshamat, com os botões Confirmar e Descartar.
O verso real de uma figurinha, fotografado sem enquadramento nenhum, e a leitura que saiu dele. O número de série impresso ao lado do código é a armadilha do problema: o reconhecedor devolve vários candidatos e quem decide qual deles existe de verdade é o catálogo de 994 cromos, não o motor.

Duas decisões seguram a precisão. A primeira é a normalização da imagem antes da leitura: foto de celular moderno chega com milhares de pixels de largura e a leitura fica confiável numa faixa bem mais estreita, então toda imagem — de câmera ou de arquivo — passa pelo mesmo redimensionamento num ponto único do código.

A segunda é que o app nunca grava sozinho. A leitura sempre termina numa pergunta com o nome do jogador junto — “KSA14 — Saleh Abu Alshamat?” — e só o toque em Confirmar mexe na coleção. Quando o motor lê lixo, a resposta é honesta: “não consegui ler”, em vez de um chute plausível. Num álbum, um chute plausível é pior que nenhuma leitura, porque some sem deixar rastro dentro de 994 linhas.

As fotos reais que o dono tirou na mesa da cozinha viraram fixtures de regressão. A troca de motor só entrou depois de passar nessa bateria inteira.

O que separa um checklist de uma ferramenta de troca

Marcar posse é o mínimo. O que o colecionador faz de verdade é conversar com outro colecionador, e a moeda dessa conversa é uma lista de texto colada num aplicativo de mensagem.

Tela de listas copiáveis com dois blocos, faltantes e repetidas, cada um com botões de copiar e compartilhar; o bloco de repetidas mostra linhas agrupadas por seleção, com bandeira, sigla e a quantidade de cada cromo entre parênteses.
As duas listas que o app existe para produzir. Agrupadas por seleção, com bandeira e sigla, prontas para colar numa conversa — e no formato que a tela de comparação sabe ler de volta.

Daí sai o recurso que fecha o ciclo: a tela de comparação aceita a lista do outro, colada como texto, e cruza com a coleção local para responder as duas perguntas da negociação — o que eu posso dar e o que ele pode me dar. O leitor de texto não exige formato: reconhece a lista exportada pelo próprio app, mas também texto solto com siglas e números, com ou sem cabeçalho, com ou sem a quantidade entre parênteses. Quando não reconhece nada, diz isso em vez de mostrar uma tabela vazia.

No mesmo espírito, a entrada em massa aceita faixas — abrir um pacote e registrar 1-20, 34, 55 de uma vez, somando ou retirando — porque a alternativa é vinte toques na grade.

A conta que o colecionador realmente faz

A pergunta que ninguém responde com uma barra de progresso é: quanto ainda vou gastar? As últimas figurinhas são as caras — quanto menos falta, mais pacote se compra para achar uma nova.

A tela de estatísticas usa esse comportamento a favor do usuário: estima quantos pacotes ainda devem ser necessários, converte em dinheiro com um preço de pacote que a pessoa edita, e compara o ritmo atual com o ritmo necessário para fechar o álbum até a data-limite. A evolução vem dos próprios carimbos de tempo das marcações — é aproximada, e a tela diz que é.

Duas peles, alvo de dedo

O app é usado em pé, com uma mão, às vezes num lugar mal iluminado. Isso pesou mais que estética: alvos de toque grandes, estado indicado por cor e por ícone, e um tema escuro de verdade — não um filtro, mas uma segunda paleta com contraste verificado nos dois modos.

A mesma grade de figurinhas da seleção do Brasil nos dois temas, claro em cima e escuro embaixo: cartões no formato de cromo com o código em destaque, o nome do jogador, marca de posse e os controles de menos e mais para a contagem de repetidas.
A mesma tela nos dois temas. O cartão imita a proporção de uma figurinha e carrega o controle de repetidas embutido, então somar uma cópia é um toque no lugar onde o olho já está.

A figurinha possuída avança visualmente e a faltante recua — o inverso do padrão de lista de tarefas, onde o item pendente grita. Aqui o que se procura na grade é o buraco, e buraco se acha mais rápido quando o resto está cheio.

As decisões que sustentam o custo zero

O app inteiro roda num Worker na borda, com o banco no SQLite gerenciado da mesma plataforma. Não há servidor ligado esperando requisição, e por isso não há conta no fim do mês.

O login é a decisão mais econômica do projeto: em vez de escrever cadastro, sessão e recuperação de senha para um usuário, o app fica atrás de um gate de identidade da própria plataforma. Zero linha de código de autenticação, zero senha guardada — e, em troca, o pitfall do redirecionamento que abre este caso, que virou o primeiro risco documentado no design e tem teste próprio.

O link deste caso, portanto, passa por esse login: o app está no ar, mas a coleção é de uma pessoa só. Os prints acima são a visita guiada.

Estado

No ar, com o catálogo real de 994 figurinhas conferido contra o checklist impresso. A suíte de unidade tem 551 casos em 65 arquivos, todos verdes, e quatro suítes de ponta a ponta guardam os fluxos que só falham rodando: a volta completa de exportar e importar, o uso offline, a convergência entre dois aparelhos e o registro do service worker atrás do gate de login.

Quer conversar sobre este projeto — ou sobre construir algo assim? Fale comigoou escreva para contato@daniel-dac.com.

Abrir o projeto ↗ · app privado, pede login

Ver os outros projetos