1

Pitch: um mapa de 3 milhões de canais do Telegram que abre com 90 KB

No TGScope a gente montou um mapa semântico de 3 milhões de canais públicos do Telegram. Canais que falam de coisas parecidas ficam perto uns dos outros, então dá para ver o ecossistema inteiro de uma vez: das grandes regiões (cripto, notícias, games) até nichos minúsculos.

Mapa: https://tgscope.io/map (gratuito, sem cadastro)

O requisito era um só: o mapa tinha que abrir em menos de um segundo, inclusive no celular. Isso descarta o caminho óbvio de mandar todos os pontos para o navegador. Abaixo, como resolvemos.

Como cada canal ganha uma posição

  1. Lemos só o perfil público do canal: título, temas, categoria e descrição. Posts e listas de inscritos ficam de fora. Os temas pesam 60% e a descrição 40%, porque descrição costuma vir cheia de contato, preço de anúncio e link.
  2. Um modelo de embeddings multilíngue transforma o perfil em vetor. Canais sobre o mesmo assunto ficam com vetores parecidos mesmo sem palavras em comum ou em idiomas diferentes.
  3. O UMAP achata centenas de dimensões em duas, preservando os vizinhos mais próximos. Cortamos 0,1% dos pontos mais extremos de cada borda para que meia dúzia de perfis estranhos não espremam o resto num canto.
  4. Os rótulos das regiões não são gerados por LLM: cada área recebe o nome dos um ou dois temas mais característicos dela em comparação com o resto do mapa. São três níveis: 25 regiões, 250 temas e 2.500 subtemas.

Por que abre tão rápido

O navegador nunca baixa o mapa inteiro.

  • Tiles em quadtree, igual a mapa de ruas. Cada tile tem no máximo 4.096 canais. O tile raiz tem os maiores canais, que já desenham o formato do mapa todo; os menores só chegam quando você dá zoom, e só para a área visível.
  • 8 bytes por canal: x e y dentro do tile (dois uint16), categoria, idioma e faixa de inscritos (um byte cada). Um tile inteiro tem uns 32 KB e o parse é só ler um array tipado:
const u16 = new Uint16Array(buf);
const u8 = new Uint8Array(buf);
for (let i = 0; i < n; i++) {
  x[i] = (tx + u16[i * 4] / 65535) / k;
  y[i] = (ty + u16[i * 4 + 1] / 65535) / k;
  cat[i] = u8[i * 8 + 4];
  lang[i] = u8[i * 8 + 5];
  tier[i] = u8[i * 8 + 6];
}
  • Primeira tela com ~90 KB de dados: manifesto (1,3 KB), rótulos (59 KB) e o tile raiz (32 KB).
  • Nome de canal não vai no tile. O servidor responde quem está por trás de um ponto quando você passa o mouse ou clica. Efeito colateral: não dá para baixar o catálogo inteiro num arquivo só.
  • WebGL 2, uma draw call por tile. Cor, tamanho e filtro de idioma são calculados no shader, então trocar o idioma é mudar um uniform — nenhum dado é recarregado.

O que dá para fazer

  • buscar por significado: descreva o que procura em vez de adivinhar o nome do canal
  • filtrar por idioma (português incluído) e ver como cada idioma forma sua própria "ilha"
  • clicar num ponto para ver o card do canal e compartilhar o link de qualquer lugar do mapa

Feedback técnico é muito bem-vindo, principalmente sobre o formato dos tiles: alguém já conseguiu algo menor que 8 bytes por ponto sem perder precisão útil?

Carregando publicação patrocinada...