Skip to content

feat(ui): Substituir seleção de linguagens por Carousel Infinito com Bandeiras Medievais Animadas #97

Closed

Description

@caioross

Objetivo

Substituir completamente o componente atual de seleção de linguagens (cards) por um carousel horizontal infinito, onde cada linguagem será representada por uma bandeira medieval vertical.

A proposta é transformar a seleção de linguagens em um elemento central da identidade visual do projeto, tornando a navegação muito mais imersiva e memorável.


Contexto

Hoje utilizamos uma lista de cards independentes para selecionar a linguagem.

A nova proposta substitui essa abordagem por um carousel infinito onde cada item representa uma linguagem através de uma bandeira medieval.

Exemplo do conceito visual:

A imagem atual contém diversas bandeiras em uma única composição e deverá ser utilizada apenas como material base.


Asset

A imagem existente contém aproximadamente 10 linguagens em uma única textura.

Ela não deverá ser utilizada inteira.

Será necessário realizar um fatiamento da imagem, gerando um asset individual para cada linguagem.

Exemplo:

typescript.png
bash.png
sql.png
ruby.png
lua.png
dart.png
scala.png
elixir.png
erlang.png
haskell.png
...

Cada banner será um item independente dentro do carousel.

Isso permitirá:

  • renderização individual;
  • animação independente;
  • futura adição de novas linguagens sem alterar o sprite original.

Carousel

O carousel deverá ser:

  • infinito
  • horizontal
  • extremamente fluido
  • desaceleração suave
  • suporte a mouse e touch
  • possibilidade futura de autoplay

O comportamento esperado lembra uma gôndola onde diversas bandeiras ficam penduradas lado a lado.


Animação das bandeiras

O objetivo não é apenas mover os banners junto com o carousel.

Cada bandeira deverá possuir uma animação própria simulando um tecido pesado.

Referência técnica:

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

A simulação deverá ser adaptada para representar:

  • tecido espesso
  • pouco elástico
  • pesado
  • amortecimento elevado
  • movimentos lentos
  • pequena inércia

Não queremos um tecido fino sendo agitado pelo vento.

Também não queremos movimentos exagerados.

A sensação deve lembrar:

  • estandartes de castelos
  • bandeiras de igrejas
  • pendões medievais
  • tecidos de veludo
  • tapeçarias

Interação com o Carousel

A física deve responder ao movimento do usuário.

Quando o carousel acelerar:

  • a parte superior acompanha imediatamente
  • o restante da bandeira atrasa levemente
  • surge uma pequena curvatura

Quando o carousel desacelerar:

  • a bandeira continua seu movimento por inércia
  • ocorre uma pequena oscilação
  • rapidamente retorna ao equilíbrio

Quando o carousel estiver parado:

  • as bandeiras permanecem praticamente imóveis
  • apenas um movimento residual extremamente sutil pode permanecer

O efeito esperado é semelhante ao de um tecido pesado preso por sua haste superior.


Diretrizes Visuais

A animação deve transmitir peso.

Evitar:

  • tremores
  • vibrações constantes
  • movimentos rápidos
  • ondas excessivas
  • comportamento semelhante a seda ou bandeiras leves

Buscar:

  • elegância
  • estabilidade
  • naturalidade
  • inércia
  • sensação de massa

O usuário deve perceber que existe uma simulação física, mas ela não deve chamar mais atenção que a interface.


Performance

A solução precisa permanecer leve.

Objetivos:

  • manter FPS elevado
  • reutilizar geometrias sempre que possível
  • evitar recriação constante de física
  • limitar a complexidade da malha de cada tecido
  • considerar pausa ou redução das simulações quando o carousel estiver ocioso

Arquitetura sugerida

Carousel
    │
    ├── Banner
    │      ├── Texture
    │      ├── Cloth Mesh
    │      └── Physics
    │
    ├── Banner
    │
    ├── Banner
    │
    └── ...

Cada bandeira deverá possuir sua própria simulação, permitindo que todas reajam de forma ligeiramente diferente ao movimento do carousel.


Critérios de Aceitação

  • Remover o componente atual baseado em cards.
  • Implementar carousel horizontal infinito.
  • Fatiar o asset original em imagens individuais por linguagem.
  • Cada linguagem deve utilizar sua própria textura.
  • Integrar Three.js com a simulação physics_ammo_cloth como base para o comportamento do tecido.
  • Adaptar a física para representar tecidos pesados.
  • Movimento do tecido deve responder à velocidade do carousel.
  • Oscilações devem ser suaves e amortecidas.
  • As bandeiras devem permanecer praticamente estáticas quando o carousel estiver parado.
  • Garantir boa performance mesmo com diversas bandeiras simultaneamente.

Resultado Esperado

Ao navegar entre as linguagens, o usuário não terá a sensação de deslizar cartões, mas de movimentar uma sequência de estandartes medievais suspensos.

Cada bandeira reage ao deslocamento do carousel com uma leve inércia, criando um movimento orgânico e elegante, reforçando a identidade visual do projeto sem comprometer a usabilidade ou a performance.

Image Image Image

Activity

  1. added
    em-resolucaoClaim: um Resolvedor está trabalhando nisto
    and removed
    em-resolucaoClaim: um Resolvedor está trabalhando nisto
    on Jul 26, 2026
  2. caioross commented on Jul 26, 2026

    @caioross
    OwnerAuthor

    Implementada em PR #98.

    Uma AC foi cumprida por outro caminho, e isso precisa do seu aval: não usei Three.js + physics_ammo_cloth. São ~700 KB (three.js ~170 KB gzip + ammo.wasm ~500 KB) para escolher uma linguagem numa home que hoje carrega 212 KB — e dependência de runtime pesada é núcleo irredutível do HANDBOOK §7.1, decisão sua. Além disso, soft-body completo é a ferramenta errada para o efeito pedido: tecido pesado, amortecimento alto e "praticamente imóvel quando parado" é um pêndulo amortecido preso por uma haste, não uma malha de partículas. O caminho entregue custa +4 KB e zero dependências, com a simulação isolada atrás de stepCloth/bendProfile — se preferir a rota ammo, troco o backend sem tocar no carousel nem nos assets.

    Demais ACs atendidas: grade de cards removida dos dois pontos de uso; carousel infinito horizontal (aritmética modular, sem lista duplicada) com arremesso, desaceleração e encaixe; mouse, touch, roda e teclado; as 3 composições fatiadas em 25 estandartes cobrindo as 24 linguagens de LANGUAGES (284 KB de WebP); pano com curvatura progressiva que só responde a aceleração — reto na rolagem lisa, chicoteia ao frear, assenta em <1,5 s; simulação desligada em repouso (o rAF dorme, custo zero por frame).

    Um detalhe que a issue não previa: a #72 transformou o seletor do lobby em votação, então lá centralizar não pode votar — o voto sai no clique/Enter (commitOnSettle={false}), com os selos de contagem preservados.

    Gate: typecheck ✅ · build ✅ (216 KB) · pnpm test 120/120 (+32) ✅ · validate-persistence 72/72 ✅ · validate-metrics 45/45 ✅.

  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
    area:uiInterface, design system, animação, game feel
    on Jul 28, 2026
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:uiInterface, design system, animação, game feel

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions