Cada ranking agora é uma tela só, e você troca o recorte dentro dela. Abra Nível Máximo, Missões da Semana ou Total de Estrelas e alterne entre Global, País e Estado sem fechar nada. Antes era o contrário: o ranking do país e o do estado eram telas separadas, e para comparar o seu nível no mundo com o seu nível no estado você precisava sair de uma e abrir a outra.
O ranking da semana agora mostra quanto tempo falta. Um contador no cabeçalho — "2d 14h" enquanto sobra folga, "18m 42s" quando é hora de correr. Antes não havia como saber quando a semana virava.
O ranking semanal passou a contar quem joga
Concluir missões diferentes na semana já coloca você no ranking. Antes era preciso bater um recorde de estrela para aparecer — então quem completasse oito missões novas na semana, sem melhorar nenhuma estrela, ficava fora de um ranking que ordena justamente por essas oito missões. Ninguém que aparecia antes deixa de aparecer.
Repetir a mesma missão não conta mais duas vezes. O número de missões da semana passou a contar missões distintas, então o ranking mede quanto do jogo você percorreu, e não quantas vezes você repetiu o nível mais rápido.
A moeda agora premia progresso
Você ganha moedas quando supera o seu próprio melhor — mais estrelas ou um tempo melhor naquela missão. Concluir de novo sem melhorar não paga. Antes toda conclusão pagava, e repetir a missão mais fácil era renda ilimitada, o que tornava sem sentido o preço de tudo na loja.
Duas conquistas diferentes na tela de vitória, que antes eram uma. "Novo Recorde Pessoal!" quando você supera a si mesmo, e "Novo Recorde!" quando você assume o 1º lugar daquela missão entre todos os jogadores. Antes só existia a segunda etiqueta, e ela aparecia em toda rejogada de quem já era o primeiro — inclusive numa corrida pior que a anterior.
Correções
O ranking global aparecia em português para quem joga em outro idioma. "Nível 42", "8 missões" e o aviso de ranking vazio estavam cravados em português na tela de ranking global, em inglês, espanhol e francês. As três agora seguem o idioma escolhido.
As moedas mostradas na tela de vitória em tela horizontal eram calculadas separadamente do valor creditado. Passaram a ser o mesmo número.
A tela saltava ao trocar de Mundo para País ou Estado. O nome da região aparecia embaixo do título só nos recortes regionais, e isso empurrava a contagem regressiva, as abas e a lista 12 pixels para baixo — com a lista perdendo a mesma altura, porque o cartão tem altura fixa. Agora os três recortes mostram a legenda, e nada se move ao trocar de aba.
Mudanças Internas
Um modal de ranking no lugar de dois. 833 linhas viraram 436. Os dois antigos eram quase-cópias com estado de carregamento, linha de pódio e lista vazia duplicados, e era essa duplicação que deixava a correção de idioma entrar num e não no outro.
A contagem regressiva espelha o relógio que define a semana, inclusive na mistura de horário local e UTC que ele tem — corrigi-la mudaria de semana o progresso de todos os jogadores. Um teste cobra que as duas concordem na virada.
O contador semanal ganhou uma lista de missões já contadas, e ele continua incremental em vez de derivar dessa lista: derivar derrubaria de 40 para 1 o número de quem atualizasse no meio da semana. Convive com a versão anterior instalada sem que nenhum dos dois lados derrube o outro.
A fila de sincronização offline mandava os campos um por um ao repor estatística, o que fazia campo novo desaparecer da nuvem sem erro nenhum. Agora manda o conjunto inteiro.
personal_record entrou no evento de fim de nível, o que torna legível a queda de volume do evento de moedas — sem essa dimensão, ela seria indistinguível de um defeito.
Toda nave agora tem luz e sombra. Uma aresta clara do lado de onde vem a luz e uma escura do lado oposto — a mesma luz que ilumina os planetas, e ela fica parada no espaço enquanto a nave gira em órbita. A nave deixou de ser uma silhueta chapada e passou a parecer um objeto.
As 13 naves agora têm o mesmo tamanho na tela. Elas eram desenhadas com diferenças grandes de tamanho entre si, e a nave inicial era a menor de todas — trocar de nave mudava o tamanho da sua nave sem aviso. Agora todas ocupam o mesmo espaço, inclusive na loja, que passou a mostrar a proporção real.
Nenhuma dessas mudanças mexe na dificuldade. A área de colisão continua idêntica para as 13 naves, como sempre foi.
Os temas sonoros têm nomes novos
Prisma, Sino, Bronze e Conquista viraram Aurora, Cristal, Forja e Apogeu. Só o nome mudou — o som de cada tema é o mesmo, e o tema que você escolheu continua escolhido.
O seletor agora marca qual é o padrão.
Correções
O lançamento da nave no tema Cristal soava como um apito. Era o único dos quatro com esse comportamento; agora pertence à mesma família dos outros três, sem perder o brilho que distingue o tema.
Mudanças Internas
O volume da nave é assado uma vez por nível, não desenhado a cada quadro. A nave virou um sprite em cache, então o efeito custa menos por quadro que o desenho anterior, mesmo sendo mais elaborado. Medido em aparelho: zero quadros perdidos.
render_ship_quality no Remote Config desliga o efeito sem republicar — 0 volta ao desenho anterior, 1 usa um sprite só com a luz presa ao casco.
O brilho da nave passou a ser medido, não estimado. Amostragem de luminância na tela do aparelho mostrou a aresta em 224 contra 143 do planeta mais claro; hoje está em 212, com 94% menos área brilhante.
Nova bancada de desenvolvimento (yarn ship:lab) com as 14 formas lado a lado, a proporção real dos planetas ao redor e medição de luminância — ela não vai para o aplicativo publicado.
Um teste passou a medir a silhueta de cada nave pelo renderizador real, o que impede que uma skin nova entre fora do tamanho.
Novo item em Configurações: Tema Sonoro. Quatro conjuntos de som para escolher, e a escolha vale para o jogo inteiro — lançamento, explosão, chegada ao planeta, estrelas, cadeado e o nível liberado. São nove sons por tema.
Prisma (padrão) — corpo quente com um brilho discreto por cima. É o som que o jogo já tinha nas partidas, agora com a comemoração combinando.
Sino — cristalino, com cauda longa.
Bronze — o mesmo desenho do Sino em timbre mais escuro e sem agudo.
Conquista — o mais próximo do som de chegar ao planeta, que é o momento que o jogo sempre acertou.
A escolha acompanha a conta, então trocar de aparelho não devolve ao padrão.
Correções
A comemoração não é mais mais alta que o resto do jogo. Ela saía bem acima do lançamento da nave — mais que o triplo no momento em que o próximo nível é liberado. Agora todos os sons estão no mesmo nível, medido.
A comemoração não soa mais desafinada. Os acordes de liberar nível e de virar de setor estavam num encadeamento que não resolvia, e ficava áspero contra a música de fundo. Foram reescritos para combinar com a trilha em qualquer ponto dela.
O estouro do cadeado parecia um bumbo seco e vinha alto demais. Agora assenta em vez de socar, e tem uma cauda em vez de terminar no golpe.
"Efeitos Sonoros" em espanhol estava escrito em português.
Mudanças Internas
O volume passou a ser medido, não estimado. Um teste reconstrói o envelope de cada som e o integra — é assim que se descobriu a diferença acima. Somar os ganhos não servia: a comemoração empilha até doze osciladores e uma partida usa um ou dois.
Os acordes declarados são verificados. Um teste recusa acorde com duas notas próximas demais, que era exatamente o defeito publicado na 1.4.1.
Bancada de som (yarn sound:lab) para comparar os conjuntos com a animação e a música rodando junto. Fica fora do que é publicado, por construção.
A comemoração de fim de nível ganhou som. A animação estreou no 1.2.1 e era muda: as estrelas acendiam, o cadeado quebrava e o setor novo abria em silêncio. Agora cada um desses momentos tem o seu som, disparado no instante exato da animação correspondente.
As três estrelas sobem de altura. Elas tocam uma frase que sobe, e não três toques iguais — a terceira estrela é a que você veio buscar, e agora ela soa como a mais difícil das três.
A música abre espaço e volta sozinha. Durante a comemoração a trilha de fundo abaixa e retorna ao normal no fim. Sem isso a celebração dividia a mesma faixa do sintetizador e virava uma mistura mais densa, em vez de um momento.
Nada disso soa fora de tom. Os sons foram escritos na mesma escala da música que toca por baixo, que é a única condição em que desafinação aparece.
O interruptor de Efeitos Sonoros vale aqui também. Com ele desligado, a comemoração roda inteira em silêncio.
Quem prefere menos movimento ouve um som só. No aparelho com "reduzir animações" ligado, a sequência inteira passa num piscar — então em vez de sete sons ao mesmo tempo, toca apenas o que resume a conquista.
Mudanças Internas
O site ganhou uma página de changelog, em português e inglês, gerada a partir destes arquivos e ligada no rodapé e no bloco de novidades. Ela era mantida à mão e por isso divergia: as landing pages passaram dois releases anunciando "versão 1.3" com o jogo já em 1.4.0. Agora um guard no gate recusa o release enquanto a página não bater com o texto daqui.
As landing pages deixaram de citar a versão à mão e passaram a descrever o estado atual do jogo. Os selos de App Store e TestFlight foram alinhados aos demais, e os emoji da página de changelog viraram ícones.
Só o conjunto de sons escolhido é embarcado. As cinco alternativas testadas e a bancada que as comparou ficam fora da versão publicada — são 1.327 bytes que o jogador não baixa.
Um interruptor, no lugar de dois. "Mostrar nome" e "Mostrar foto" viraram "Entrar nos rankings como anônimo". Meio anonimato não protegia ninguém — a foto do Google identifica tão bem quanto o nome. Quem já tinha desmarcado qualquer um dos dois entra anonimizado, sem precisar reconfigurar.
A preferência passou a ser respeitada de verdade. Ela existia e era ignorada em três caminhos independentes: o ranking global era reescrito com o nome real ao fim de cada nível, o ranking de missão nunca consultava a preferência (e sem dados caía no nome da conta Google), e o login com Google copiava o nome real para todas as entradas do jogador. Um quarto caminho vazava pela fila offline: jogar sem rede e reconectar publicava nome e foto.
Trocar a preferência alcança o que já está publicado. Cada documento de ranking guarda a própria cópia do nome, então mudar a configuração não bastava. Agora o global, os semanais de todas as semanas e os de cada missão são reescritos — e a reescrita se repete até dar certo.
A tela de Perfil mostra o que vai ao ar. Um bloco novo exibe exatamente o nome e a foto que os outros jogadores veem, com o gerador de nome anônimo ao lado quando ele é o que vale.
Melhorias
A tela de Perfil cabe sem rolagem. Num Redmi Note 10 (393×873) o conteúdo passava 105px da área visível, deixando os controles de privacidade abaixo da dobra enquanto o botão Salvar seguia visível — a tela parecia inteira e não estava. Hoje sobra folga até num 360×640.
A sua linha é destacada nos rankings. No global e nos regionais, sua entrada aparece em azul, como já acontecia no fim de missão. O bloco "sua posição" no rodapé agora só aparece quando você não está na lista.
Mudanças internas
Os rankings públicos deixaram de carregar dado que ninguém lia. Saíram cidade, fuso horário e nome do país (fica o código do país, para a bandeira, e o estado, que alimenta o ranking regional), além de perfectMissions e totalPlayTime — os dois entravam só no cálculo da pontuação e nenhuma tela os usava.
check:ranking-privacy entrou no gate. Ele recusa qualquer escrita em coleção pública que monte nome, foto ou localização fora do ponto único de decisão. Achou um vazamento que a revisão manual não tinha visto.
yarn firestore:backfill-privacy reescreve os documentos já gravados, para alcançar quem não voltar a jogar. Dry-run por padrão.
De 30 para 95 fps no Motorola Edge 60 Neo. O motor pintava o equivalente a ~2,45 telas cheias por frame, e 85% disso eram duas passadas full-screen com shader de gradiente. Frame de 32 ms antes, 11 ms depois, com a GPU em 4 ms de mediana. Medido com dumpsys gfxinfo em build de release, não em emulador.
O fundo virou bitmap cacheado. O gradiente radial de tela cheia era reconstruído a cada frame; agora é pré-renderizado por (tema, tamanho do backbuffer) e blitado 1:1. O custo era recente e passou despercebido porque o ramo era morto: só 8 dos 18 temas declaravam gradiente e o primeiro alcançável era o do nível 1001 — até então o caminho real era um fill sólido.
A vinheta saiu do canvas e virou CSS. Ela custava uma tela cheia de gradiente com alpha blend por frame para entregar alpha máximo de 0,053, e só nos quatro cantos. Paridade conferida contra o render do navegador: 0 de 367.928 pixels com diferença perceptível.
Um frame descartado por segundo, que ninguém via. O laço de render é recriado a cada segundo pelo timer de missões, e o corpo do efeito reescrevia canvas.width — o que limpa a superfície mesmo com valor idêntico. Aparecia como engasgo no movimento da nave, não na média de FPS.
Taxa de tela
O jogo destrava 120 Hz em painéis que suportam. Ficava preso em 61 fps e não era limite de render: a janela não pedia taxa nenhuma ao Android, e sem pedido o sistema assume 60 Hz. Em painel de taxa única nada muda.
Tremor de tela e densidade de rastro deixaram de depender da taxa de quadros. O tremor durava o dobro em aparelho a 30 fps, e o rastro ficava mais ralo. Os dois agora são medidos em tempo. A simulação de física já era, então trajetória, órbita e recordes de tempo não mudam.
Mudanças Internas
Guia de agentes reconciliado com o repo (contagens de i18n, testes, scripts e linhas), mais duas armadilhas documentadas: as landing pages são irmãs espelhadas fora do format:check, e o marcador @DEV_ONLY é inerte — o bloco que ele envolve é público.
Seção escrita em 07/08/2026, a partir dos commits: o release foi cortado sem nota no CHANGELOG.
Loja
A loja tinha 30 cards e zero compráveis para conta nova, e o eixo de navegação era tipo de item — o jogador novo abria direto em "Equipar". Reorganizada, com badge "Novo" para a recompensa de setor ficar encontrável, e caminho até a loja de moedas, que simplesmente não existia.
Tocar num card mostra o item na nave do jogador, em vez de num preview solto.
Dois toques rápidos davam duas naves pelo preço de uma.
Correções de preview: nave era um bitmap de 48 px em upscale de 2×, o rastro de 750 moedas aparecia laranja chapado, as miniaturas divergiam da nave do jogo, e "Sentinela Nova" e "Verde Esmeralda" eram o mesmo foguete verde.
Economia e recompensa
Concluir o setor 1 dá uma nave, em vez de só destravar o nível 26.
O jogador é avisado da recompensa, e um aviso deixou de apagar o outro.
Multiplicador de preço por Remote Config, para responder "exagerei no preço?" sem republicar na loja.
Visual
Planetas deixam de ser círculos chapados: atmosfera, terminador dia/noite e rim light, com a luz fixa no mundo.
Gradiente de fundo parava no nível 400, e os anéis ficavam chapados.
O pacote cosmético grátis parou de parecer inacabado.
Splash de partículas nas estrelas da trilha, com a rajada mais encadeada.
Correções
Aviso de mecânica reabria a cada nova sessão — o controle era de memória, e com a janela de 25 níveis o tutorial voltava enquanto o jogador estivesse no setor.
Faixas brancas nas barras do sistema em WebView desatualizada.
Mudanças Internas
Onze eventos de analytics para a loja parar de ser ajustada no escuro, plugin nativo do Firebase Analytics nos dois projetos, e os eventos passam a ir para o stream Android com o payload de push por allowlist.
Manipulação de cor centralizada em colorUtils, com teste.
A vitória agora acontece na trilha. "Continuar" volta para o mapa em vez de ir direto ao próximo nível: as estrelas conquistadas acendem uma a uma, o cadeado do nível seguinte quebra, e o jogador decide se joga. Pulável a qualquer toque, e respeita prefers-reduced-motion.
Mudança de fluxo, e é deliberada: custa um toque a mais entre um nível e o próximo, em troca de 20 passagens pela trilha numa sessão de 20 níveis — onde ficam loja, energia, ranking e caixa de entrada, que antes não tinham impressão nenhuma no fluxo. Vale medir com o evento de fim de nível que já existe.
Nó de nível bloqueado voltou a ser visível. O preenchimento era exatamente a cor do fundo (contraste 1,00:1, contra o mínimo de 3:1 da WCAG) — quebrar um cadeado invisível sobre um nó invisível não lia como nada.
Campo estelar com profundidade real
O céu era chapado do nível 101 em diante. O brilho por distância era montado por substituição de string e só funcionava com cor em rgb(); 17 dos 18 temas de fundo declaram hex, então a opacidade nunca era aplicada — sem erro nem aviso. Como o fundo troca a cada 4 setores, só os níveis 1–100 tinham profundidade.
Profundidade coerente: tamanho e velocidade agora saem de um mesmo depth. Antes eram sorteios independentes, então existia estrela grande e lenta — o olho lê tamanho como "perto" e lentidão como "longe", e a contradição achatava a cena.
Cintilação com fase e ritmo próprios por estrela, e estrelas de 4 pontas nos 7% mais próximos. Tudo desligado em performanceMode.
Ficou mais barato que antes: o laço passou a ser por faixa de opacidade — 6 fillStyle e 6 fill() por frame, contra até 300 strings e 300 fill().
Mudanças Internas
utils/levelCelebration.ts decide o roteiro da celebração como função pura, com 10 casos de teste — incluindo rejogar sem melhorar e a travessia entre setores.
Release de Android deixou de depender da toolchain de iOS (android:sync:*).
Release grande: 43 commits desde a 1.1.7. Atende duas políticas da Play Store com prazo, corrige perda e vazamento de dado de jogador, e traz o jogo para o comportamento obrigatório do Android 16.
Conformidade com a Play Store
Target API 36 (Android 16) via Capacitor 8, com toda a matriz AGP/Gradle acompanhando. Sem isso não seria possível publicar atualização após 01/11/2026 — o que travaria também as correções de segurança pendentes.
Google Play Billing Library 8, via RevenueCat 13.x. Mesma data-limite, política independente.
Alinhamento de página de 16 KB verificado no artefato, não só declarado no manifest. Hoje o app não tem biblioteca nativa desalinhada, e a checagem roda a cada build de release para que o primeiro plugin que trouxer uma não passe batido.
Correções que afetam dado de jogador
Progresso deixa de ser sobrescrito por progresso resetado. Três defeitos no caminho de escrita de perfil, todos encontrados por teste de invariante sobre sequências: a fila offline perdia operação por corrida, reproduzia snapshot velho sobre dado novo, e um perfil default apagava o saldo de moedas. Progresso agora é reconciliado por join — recorde por máximo, melhor tempo por mínimo — e não por relógio.
A fila offline deixa de cruzar entre contas. Uma fila criada em sessão anônima drenava dentro da conta que logasse depois, levando junto o displayName.
O cache de ranking vazava rank e nome de outra conta, no login anônimo → Google e ao abrir o ranking antes do auth resolver.
Leitura de /users fechada ao dono nas Security Rules.
permission-denied deixa de se disfarçar de erro de rede — falha de regra era indistinguível de lista vazia, e foi assim que uma regressão passou.
Jogabilidade e economia
Tutorial de mecânica volta a aparecer nos seis marcos. A versão anterior exigia a mecânica no primeiro nível do setor; como a geração é determinística, luas, portais e sistemas orbitantes caíam em níveis sem a mecânica e o tutorial era descartado para todo jogador.
Dificuldade das estrelas passa a ser ajustável por Remote Config — margens de dano, fronteiras de dificuldade e limiares de tempo saíram de literais no código.
Recompensa diária passa a exigir dois dias consecutivos.
Valor publicado no Remote Config volta a chegar ao jogo, com o guard passando a exigir override e fetch. E o default do cooldown de anúncio respeita o próprio piso.
Visual
HUD respeita os insets em edge-to-edge, obrigatório a partir do target 36.
Segurança do build
Build de produção endurecido: sem depuração de WebView, sem tráfego em texto claro e sem backup automático.
Segredos de assinatura fora do bundle e sem valor default no Gradle — tarefa de release sem eles falha na hora, com instrução do que definir.
Mudanças Internas
firestoreService dividido em 13 módulos por domínio; árvore de fonte movida para src/; geometria de nível, economia de missão e árvore de modais extraídas do App.tsx para módulos próprios com teste.
Gate de qualidade com 9 etapas, incluindo cinco validadores próprios (i18n, remote config, versão, constantes compartilhadas e catálogo de scripts).
Comportamento das firestore.rules congelado por characterization test sobre o emulador.
Scripts do package.json reorganizados por destino, com catálogo em yarn scripts.
Cooldown de recompensa via Remote Config: o cooldown do anúncio recompensado passou a ser configurável remotamente (rewarded_ad_cooldown_seconds), com piso de segurança de 180s aplicado em applyConfigOverrides
Nota: a versão 1.1.4 foi pulada na numeração — não houve release.