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
- 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.
- 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.
- 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.
- 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?
Fonte: https://tgscope.io/map