Skip to content

feat(lobby): Refinar UX do Carousel de Linguagens, restaurar votação e sincronização entre telas #99

Closed

Description

@caioross

Objetivo

Após a implementação do novo carousel de bandeiras, alguns ajustes de UX, comportamento e integração ainda são necessários para que a experiência fique consistente e pronta para uso.

Esta issue reúne refinamentos visuais, melhorias de layout, restauração de funcionalidades que deixaram de funcionar e integração entre as telas da aplicação.


1. Reorganização do Layout

A gôndola se tornou o elemento principal da seleção de linguagens e deve ganhar mais destaque na interface.

Alterações

  • mover o carousel para uma posição mais alta dentro do card
  • aproximá-lo do título "Linguagem — Votação"
  • reduzir o espaço vazio acima dele

Além disso, os botões de ação não fazem mais sentido próximos ao topo da tela.

Mover:

  • Compartilhar
  • Ficar Pronto / Iniciar Partida

para a parte inferior do card, agrupando-os junto das demais configurações da sala.

O objetivo é deixar toda a área de configuração concentrada em um único bloco visual.


2. Remover fundo da gôndola

Hoje o carousel possui um fundo escuro que acaba escondendo parte da estética das bandeiras.

Remover completamente esse fundo.

O resultado esperado é que apenas as bandeiras fiquem visíveis sobre o fundo da própria aplicação, criando uma sensação de que estão realmente suspensas no ambiente.


3. Animação física das bandeiras

Embora o novo carousel esteja extremamente fluido, as bandeiras ainda permanecem praticamente rígidas.

Conforme definido na issue anterior, elas devem utilizar uma simulação baseada no exemplo oficial do Three.js:

https://threejs.org/examples/#physics_ammo_cloth

A ideia não é criar tecidos leves.

Os parâmetros devem transmitir a sensação de:

  • estandartes medievais
  • veludo
  • tapeçarias
  • tecidos espessos
  • bastante amortecimento
  • pouca elasticidade
  • movimentos suaves

As bandeiras devem reagir ao deslocamento do carousel através de uma pequena inércia.

Quando o usuário movimenta a gôndola:

  • a haste acompanha imediatamente
  • o tecido atrasa levemente
  • ocorre uma pequena curvatura
  • após parar, a bandeira realiza uma ou duas oscilações discretas antes de estabilizar

Evitar movimentos exagerados ou chamativos.

O objetivo é adicionar vida à interface sem distrair o jogador.


4. Destacar melhor a linguagem selecionada

Hoje a linguagem central ainda não se diferencia o suficiente das demais.

A linguagem atualmente selecionada deve ficar imediatamente reconhecível.

Sugestões:

  • aumentar levemente sua escala
  • melhorar a iluminação
  • aumentar contraste
  • reduzir opacidade das linguagens laterais
  • reforçar profundidade

O usuário deve identificar instantaneamente qual linguagem está sendo escolhida.


5. Restaurar sistema de votação

Após a refatoração do componente, o sistema de votação deixou de funcionar corretamente.

Revalidar toda a lógica envolvendo:

  • seleção da linguagem
  • alteração do voto
  • sincronização entre jogadores
  • atualização em tempo real
  • vencedor da votação

Garantir que o comportamento existente antes da substituição dos cards seja preservado.


6. Propagação da linguagem entre telas

Ao criar uma nova sala, o usuário escolhe uma linguagem inicial.

Essa informação atualmente não está sendo propagada corretamente para a tela da lobby.

Como consequência:

  • a linguagem selecionada na criação é perdida
  • o carousel inicia em posição incorreta
  • estado inicial fica inconsistente

Garantir que:

  • a linguagem escolhida na criação da sala seja enviada corretamente
  • o lobby seja aberto já centralizado nessa linguagem
  • todos os jogadores recebam o mesmo estado inicial

Critérios de Aceitação

Layout

  • Mover o carousel para uma posição mais alta dentro do card.
  • Agrupar Compartilhar e Ficar Pronto junto às demais ações na parte inferior.

Visual

  • Remover o fundo escuro da área da gôndola.
  • Exibir apenas as bandeiras sobre o fundo da aplicação.
  • Destacar visualmente a linguagem central selecionada.

Física

  • Integrar a animação baseada em physics_ammo_cloth.
  • Configurar o tecido como pesado, com alta inércia e amortecimento.
  • Fazer as bandeiras reagirem suavemente ao movimento do carousel.

Funcional

  • Restaurar completamente o sistema de votação.
  • Sincronizar votos entre todos os jogadores.
  • Propagar corretamente a linguagem escolhida na criação da sala para o lobby.
  • Inicializar o carousel já centralizado na linguagem selecionada.

Resultado Esperado

O carousel deve se consolidar como o principal elemento de interação da seleção de linguagens.

As bandeiras passam a ocupar posição de destaque na interface, aparentando estar realmente suspensas por uma gôndola. A linguagem selecionada torna-se imediatamente identificável, os estandartes respondem ao movimento com uma animação física suave e elegante, e toda a lógica de votação e sincronização entre criação da sala e lobby volta a funcionar corretamente, garantindo uma experiência visualmente rica e consistente para todos os jogadores.

Activity

  1. added
    bugSomething isn't working
    area:multiplayerSalas, Realtime, presença, leaderboard, persistência
    area:uiInterface, design system, animação, game feel
    on Jul 26, 2026
  2. caioross commented on Jul 26, 2026

    @caioross
    OwnerAuthor

    Resolvida em PR #98 — como commit adicional (4731470) na PR da #97, que ainda não mergeou: esta issue é correção daquele código, e separar viraria "eis a coisa, eis a correção dela" para o revisor.

    Item 5 (votação) — causa raiz encontrada, e ela era minha: setPointerCapture no pointerdown da gôndola fazia o navegador entregar o click ao elemento de captura em vez do estandarte. No lobby, onde clicar é a única forma de votar, isso matava a votação inteira. A captura agora só entra depois de 6 px de arrasto. Passou despercebido na #97 porque eu verifiquei com .click() sintético, que ignora captura de ponteiro — reproduzi com clique real e confirmei a correção do mesmo jeito. A fiação de votos (broadcast, tally, vencedor) nunca foi tocada.

    Item 3 (física) — o sintoma era calibração, não o motor: "praticamente rígidas" estava certo e dá para medir — o ganho antigo produzia θ≈0.027 rad na desaceleração de um arremesso, ou seja menos de 1 px de ponta. Recalibrado, a trajetória real agora é -0.274 → -0.108 → +0.083 → -0.025: ~13 px num estandarte de 49 px, uma oscilação forte e duas discretas. Também passei a cisalhar cada faixa pela inclinação local, senão o pico virava escada em vez de curva.

    Itens 2 e 4: os 25 assets foram refatiados com alpha (recorte por scanline, que não entra no veludo escuro — era ali que as tentativas anteriores falhavam). Gôndola sem fundo/borda, com máscara nas pontas; central com escala 1.0 vs 0.7, opacidade 1.0 vs 0.22, brilho 1.14 vs 0.5 e halo verde na silhueta.

    Itens 1 e 6: gôndola encostada no título, ações agrupadas no rodapé do card. Sobre a propagação: a API já gravava a linguagem certo — o erro era a gôndola do lobby abrir sempre no primeiro estandarte; a nova prop centerOn centraliza na linguagem da sala enquanto não há voto.

    Gate: typecheck ✅ · build ✅ (216 KB) · 122 testes ✅ · validate-persistence 72/72 ✅ · validate-metrics 45/45 ✅.

    Dois limites que não escondo: não consigo ver a animação rodando (o Browser pane não compõe frames — a trajetória acima saiu do stepCloth real), e sem credenciais Supabase no worktree não testei a sincronização de votos entre dois jogadores de verdade.

    A AC de Three.js + ammo.js segue aberta e é decisão sua. Não incluí porque o que causava a rigidez era a calibração, já corrigida com número em cima, e o custo (~700 KB contra 216 KB de first load hoje, mais reescrever a camada de render e a acessibilidade) não mudou. Se ainda quiser essa rota depois de ver rodando, é só dizer: a simulação está isolada atrás de stepCloth/bendProfile e eu troco o backend sem tocar em carousel, assets ou votação.

  3. caioross commented on Jul 26, 2026

    @caioross
    OwnerAuthor

    Backend ammo + Three.js implementado na PR #98 (commit 2072d33), conforme a decisão do dono registrada na PR (núcleo §7.1). Fecha a última AC pendente destas duas issues.

    O soft-body do Bullet substituiu o pêndulo analítico atrás da fronteira ClothEngine; carousel, os 25 estandartes, banners.ts e a votação seguem intactos. Carregado por import() dinâmico: first load da home inalterado em 216 kB, com three + ammo em chunks sob demanda (437 kB brotli). Custo medido: 3,22 ms por quadro com 7 panos ativos, contra 16,7 ms de orçamento a 60fps.

    Medido no navegador dirigindo o laço na mão e lendo o framebuffer: ponta atrasa 12 px no arremesso com o topo cravado na haste, duas oscilações discretas ao soltar, repouso em 2,8 s. Fallback para o motor leve preservado (sem WebGL, import falhando ou reduced-motion).

    Detalhes, números e os dois defeitos de calibração que apareceram medindo estão no comentário da PR.

  4. added
    P2Prioridade normal
    blockedDepende de algo externo
    on Jul 28, 2026
  5. caioross commented on Jul 28, 2026

    @caioross
    OwnerAuthor

    Marcada blocked na triagem de hoje — sem mudança de escopo nem de prioridade.

    Esta issue é o refinamento do carousel que a #97 implementa ("Após a implementação do novo carousel, alguns ajustes..."), e a PR #98 — que fecha a #97 — está DRAFT + decisao-dono desde 26/07, aguardando o dono decidir sobre a dependência pesada (three.js + ammo, 600 KB gzip medidos, núcleo §7.1) na discussion #102.

    Trabalhar nos refinamentos agora seria construir sobre uma base que pode mudar de backend antes de mergear — retrabalho garantido, e o Resolvedor bateria na mesma parede.

    Destrava sozinha assim que a #102 for decidida e a #98 mergear. Nenhuma ação necessária aqui até lá.

  6. caioross commented on Jul 29, 2026

    @caioross
    OwnerAuthor

    🗂️ Triagem do Curador · 2026-07-29 — desbloqueada e entregue: fechando

    A PR #98 foi mergeada por @caioross em 28/07 16:24Z (82f7817), com a mensagem referenciando (#97, #99). Isso derruba o motivo do blocked que eu mesmo pus aqui em 28/07 ("destrava sozinha assim que a #102 for decidida e a #98 mergear").

    Antes de mexer no rótulo eu conferi AC por AC contra origin/main — não confiei na mensagem do merge. As 12 caixas estão implementadas:

    Layout

    Visual

    • Fundo escuro removido → globals.css:124-130: "Sem fundo próprio: os estandartes ficam suspensos sobre o fundo da aplicação". Detalhe que mostra que o item foi entendido, não só marcado: brilho e sombra foram para filter/drop-shadow em vez de box-shadow — este último redesenharia a caixa retangular e devolveria exatamente a moldura que você pediu para tirar.
    • Destaque do central → globals.css:142-146 ([data-centered="true"]), escrito pelo rAF em BannerCarousel.tsx:209 — sem re-render do React. Estado distinto do escolhido (aria-checked → halo verde, :149-151), que era necessário porque aqui dá para navegar sem votar.

    Física

    • physics_ammo_cloth integrado → src/lib/cloth/ammoCloth.ts (soft-body do Bullet atrás da fronteira ClothEngine), carregado por import() dinâmico.
    • Pesado/amortecido e reagindo ao carousel → laço em BannerCarousel.tsx:292-315. Números medidos no comentário da PR: ponta atrasa 12 px no arremesso, duas oscilações ao soltar, repouso em 2,8 s; 3,22 ms/quadro com 7 panos contra 16,7 ms de orçamento.

    Funcional

    • Votação restaurada e sincronizada → Lobby.tsx:29-32 e :49-57, com badges={voteTally} e leadingIds no carousel. O commitOnSettle={false} de :139-142 resolve um problema que a issue não previu: sem ele, arrastar votaria em cada linguagem que passasse pelo centro.
    • Linguagem da criação propagada e carousel já centralizado nela → centerOn={room.settings.language} em Lobby.tsx:145, consumido em BannerCarousel.tsx:108 e :379-392, que trata explicitamente a chegada tardia do centerOn (no lobby a sala carrega depois da primeira pintura) e para de seguir a sala assim que o jogador vota.

    Fecho como concluída em vez de só tirar o blocked: com as 12 ACs verdes, deixar aberta faria a issue disputar a fila com trabalho que ainda não existe. Se algum item ficou aquém do que você imaginou — em especial o peso percebido do tecido e a nova posição dos botões, que são julgamento visual e eu não tenho como medir — reabra ou abra a fatia de ajuste; a base agora está em produção para comparar.

    Uma coisa que a entrega não cobre e que não é AC daqui: as animações do carousel honram prefers-reduced-motion (BannerCarousel.tsx:100,292,404,480), mas boa parte do resto da UI não — abri a #108 para isso.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Prioridade normalarea:multiplayerSalas, Realtime, presença, leaderboard, persistênciaarea:uiInterface, design system, animação, game feelbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions