Communitygithub.com

ZainR525/PersonalWebsiteZainRizvi

Abordagem da Apple para design de interfaces e movimento físico e fluido, traduzida para a web. Use ao construir ou revisar interfaces orientadas por gestos, animações com mola, interações de arrastar/deslizar/folha, momentum e transições interrompíveis, materiais translúcidos e profundidade, tipografia (tamanho óptico, tracking, entrelinha), movimento reduzido ou os fundamentos de design (feedback, consistência espacial, moderação) por trás das interfaces no estilo Apple.

O que é PersonalWebsiteZainRizvi?

Este skill traduz os princípios de design de interface da Apple — especificamente das palestras da WWDC, como *Designing Fluid Interfaces* (WWDC 2018) — para plataformas web modernas usando CSS, Pointer Events, `requestAnimationFrame` e bibliotecas de mola como Motion e Framer Motion. O foco central é que uma interface parece viva quando o movimento começa a partir do valor atual na tela, herda a velocidade do usuário, projeta o momentum para frente e pode ser agarrada e revertida a qualquer instante. Para desenvolvedores web, isso se traduz em diretrizes práticas para eliminar latência, implementar rastreamento 1:1 com truques como `setPointerCapture`, usar molas (com parâmetros de amortecimento e resposta) para animações interrompíveis em vez de transições CSS de duração fixa, e projetar momentum no final dos gestos para criar movimento de arremesso. O skill também detalha consistência espacial (caminhos simétricos para entrada/saída), efeitos de rubber-banding para limites suaves e materiais translúcidos com `backdrop-filter` para transmitir hierarquia — tudo com exemplos de código e valores concretos que a Apple utiliza, como `damping: 1.0, response: 0.4` para movimentação. É útil para qualquer desenvolvedor que deseje construir desde modais e painéis deslizantes até carrosséis e interfaces multitoque responsivas no estilo Apple, enfatizando que a suavidade vem do que está nos quadros, e não apenas da taxa de quadros.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ZainR525/PersonalWebsiteZainRizvi/tree/HEAD/.claude/skills/apple-design

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Design Apple

Resposta Inicial

Quando este skill for invocado pela primeira vez sem uma pergunta específica, responda apenas com:

Estou pronto para ajudar você a construir interfaces fluidas no estilo Apple para a web. Meu conhecimento vem das palestras de design da WWDC da Apple, traduzido para a web.

Não forneça nenhuma outra informação até que o usuário faça uma pergunta.

Como a Apple constrói interfaces que deixam de parecer um computador e começam a parecer uma extensão sua. Este conhecimento vem das palestras de design da WWDC da Apple — principalmente Designing Fluid Interfaces (WWDC 2018) — destilado e traduzido para a plataforma web (CSS, Pointer Events, requestAnimationFrame, bibliotecas de mola como Motion/Framer Motion).

A linha central: uma interface parece viva quando o movimento começa a partir do valor atual na tela, herda a velocidade do usuário, projeta o momentum para frente e pode ser agarrada e revertida a qualquer instante. Molas são a ferramenta que torna tudo isso natural, porque são inerentemente interrompíveis e conscientes da velocidade.

A Ideia Central

"Quando alinhamos a interface à maneira como pensamos e nos movemos, algo mágico acontece — ela deixa de parecer um computador e começa a parecer uma extensão natural de nós mesmos."

Uma interface é fluida quando se comporta como o mundo físico: as coisas respondem instantaneamente, movem-se continuamente, carregam momentum, resistem nos limites e podem ser redirecionadas durante o movimento. Tudo abaixo é uma maneira de chegar mais perto disso.

A Apple enquadra o design como servindo a quatro necessidades humanas: segurança/previsibilidade, compreensão, realização e alegria. Cada regra aqui serve a uma delas.

1. Resposta — elimine a latência

No momento em que a latência aparece, a sensação de imediatismo "cai de um precipício". A resposta é a base sobre a qual todo o resto é construído.

  • Responda ao pressionar o ponteiro, não ao soltar. Destaque um botão no instante em que é pressionado. Esperar pelo evento click/toque para mostrar feedback parece morto.
  • Seja vigilante com cada latência. Audite debounces, temporizadores artificiais, esperas de transição e o atraso de toque de ~300ms. Qualquer coisa no caminho de entrada que não seja essencial é uma regressão.
  • O feedback deve ser contínuo durante a interação, não apenas no final. Para um arrasto, controle deslizante ou gaveta, atualize a interface 1:1 com o ponteiro durante todo o percurso — nunca anime apenas quando o gesto for concluído.
/* O feedback vive no pressionar, e é instantâneo */
.button:active {
  transform: scale(0.97);
  transition: transform 100ms ease-out;
}

2. Manipulação direta — rastreamento 1:1

"Toque e conteúdo devem se mover juntos."

Quando o usuário arrasta algo, ele deve permanecer grudado ao dedo — e respeitar o deslocamento de onde foi agarrado. Ajustar para o centro do elemento ao agarrar quebra a ilusão imediatamente.

  • Use Pointer Events com setPointerCapture para que o rastreamento continue mesmo quando o ponteiro sair dos limites do elemento.
  • Rastreie um breve histórico de posição/velocidade (últimos eventos pointermove), não apenas o ponto atual — você precisará da velocidade ao soltar.
el.addEventListener('pointerdown', (e) => {
  el.setPointerCapture(e.pointerId);
  const grabOffset = e.clientY - el.getBoundingClientRect().top; // respeita onde foi agarrado
  // ...rastreia histórico de posição + timestamp para velocidade
});

3. Interrompibilidade — o princípio mais importante

"O pensamento e o gesto acontecem em paralelo."

Cada animação deve ser interrompível e redirecionável a qualquer momento. Um usuário deve ser capaz de agarrar um elemento em movimento no meio do trajeto e revertê-lo sem esperar a animação terminar. Um modal que está fechando e o usuário agarra novamente deve seguir o dedo — não terminar de fechar primeiro e depois reabrir.

  • Nunca bloqueie a entrada durante uma transição.
  • Sempre anime a partir do valor presente (atual), nunca do valor alvo. Ao interromper, leia a transformação ativa na tela do elemento e inicie a nova animação a partir dela. Começar a partir do valor lógico/alvo causa um salto visível.
  • Evite transições CSS e @keyframes para qualquer coisa orientada por gestos — elas não podem ser suavemente agarradas e revertidas durante o movimento. As molas animam a partir do valor atual por padrão, que é exatamente o que a interrupção precisa.
  • Quando um gesto reverte, misture a velocidade — não faça um corte brusco. Substituir uma animação por outra em uma reversão cria uma descontinuidade de velocidade, uma "parede de tijolos". Bibliotecas de mola que carregam a velocidade através de um novo alvo evitam isso. (É isso que as animações aditivas do iOS fazem nativamente; na web, escolha uma biblioteca de mola que mire novamente a partir da velocidade atual.)
  • Decomponha o movimento 2D em molas independentes para X e Y. Uma única mola em uma distância 2D dessincroniza quando X e Y têm velocidades diferentes.

4. Comportamento sobre animação — use molas

"Pense na animação como uma conversa entre você e o objeto, não algo prescrito pela interface."

Uma animação pré-roteirizada e de duração fixa não pode responder a novas entradas. Uma mola pode — uma nova entrada apenas muda o alvo, e o movimento permanece contínuo. Recorra a molas para qualquer coisa que o usuário possa tocar.

A Apple deliberadamente substituiu o trio da física (massa/rigidez/amortecimento) por dois parâmetros mais amigáveis ao designer. Pense neles:

  • Razão de amortecimento — controla o overshoot. 1.0 = criticamente amortecido, sem oscilação, ajuste suave. < 1.0 = overshoot e oscila. Quanto menor, mais saltitante.
  • Resposta — quão rapidamente o valor atinge o alvo, em segundos. Menor = mais rápido. Isso não é 'duração' — uma mola não tem duração fixa; seu tempo de acomodação emerge dos parâmetros.

Padrões:

  • Comece a maioria das interfaces com amortecimento 1.0 (criticamente amortecido) — gracioso e não distrativo.
  • Adicione oscilação (amortecimento ~0.8) apenas quando o gesto em si carregou momentum (um arremesso, um lançamento, uma liberação de arrasto). Overshoot em um menu que apenas apareceu parece errado; overshoot em um cartão que você arremessou parece certo.

Valores concretos que a Apple utiliza:

InteraçãoAmortecimentoResposta
Mover / reposicionar (ex.: PiP)1.00.4
Rotação0.80.4
Gaveta / folha0.80.3

Mapeamento web (Motion / Framer Motion): a API de mola bounce + duration mapeia de perto o amortecimento + resposta da Apple. Um estilo seguro padrão é usar molas com damping: 1.0 em toda parte por padrão; reserve a oscilação para interações físicas com momentum.

import { animate } from 'motion';

// Padrão criticamente amortecido (sem overshoot)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });

// Interação com momentum — um pouco de oscilação, apenas porque um arremesso precedeu
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });

5. Transferência de velocidade — a costura entre arrasto e animação

Quando um gesto termina, a animação deve continuar na velocidade exata do dedo, para que não haja costura visível entre arrastar e animar. Este é o detalhe que mais separa o 'fluido' do 'bom'.

Passe a velocidade de liberação do ponteiro como a velocidade inicial da mola. Algumas APIs de mola querem velocidade relativa — normalize-a pela distância restante até o alvo:

velocidadeRelativa = velocidadeDoGesto / (valorAlvo − valorAtual)

Exemplo: elemento em y=50, alvo y=150 (100px para percorrer), dedo movendo a 50px/s → velocidade inicial da mola = 50 / 100 = 0.5. Framer Motion / Motion aceitam velocidade absoluta em px/s diretamente (opção velocity), então geralmente você passa o valor bruto.

6. Projeção de momentum — anime para onde o gesto está indo

"Pegue uma pequena entrada e produza uma grande saída."

Não ajuste para o limite mais próximo a partir do ponto de liberação. Use a velocidade para projetar a posição de repouso — exatamente como a desaceleração de rolagem — e então ajuste para o alvo mais próximo desse ponto projetado. Isso é o que faz um arremesso parecer que está lançando o elemento.

A função de projeção exata da Apple (do código de exemplo de Designing Fluid Interfaces):

// decelerationRate ≈ 0,998 para sensação de rolagem normal; 0,99 para mais rápido
function project(initialVelocity /* px/s */, decelerationRate = 0.998) {
  return (initialVelocity / 1000) * decelerationRate / (1 - decelerationRate);
}

const projectedEndpoint = currentPosition + project(releaseVelocity);
const target = nearestSnapPoint(projectedEndpoint);   // escolhe o alvo a partir da projeção
animateSpringTo(target, { velocity: releaseVelocity }); // então transfere a velocidade (§5)

Nota: a fórmula física v²/(2·decel) não é o que a Apple utiliza — use a forma de decaimento exponencial acima. Este é o comportamento padrão em bons bottom-sheets e carrosséis (Vaul, Embla).

7. Consistência espacial — caminhos simétricos, origens ancoradas

"Se algo desaparece de uma maneira, esperamos que ele surja de onde veio."

  • Entre e saia pelo mesmo caminho. Um painel que desliza da direita deve desaparecer para a direita. Entrada pela direita / saída por baixo parece desconexo e confuso.
  • Âncore as interações à sua origem. Um menu, popover ou folha deve se originar do elemento que o acionou — defina transform-origin para o acionador, para que a relação espacial entre botão e conteúdo seja óbvia. (Este é o mesmo ponto de consciência de origem que popovers que escalam a partir do seu acionador, não do seu centro.)
  • Espelhe a suavização em transições reversíveis para que o caminho de saída corresponda ao caminho de retorno (use pontos de controle cúbicos-bezier inversos para as duas direções).

8. Dica na direção do gesto

Os humanos preveem um estado final a partir de uma trajetória. Os quadros intermediários devem telegrafar para onde as coisas estão indo — os módulos da Central de Controle "crescem para cima e para fora em direção ao seu dedo". Faça com que os quadros intermediários apontem para o resultado, não apenas interpolem cegamente para ele.

9. Rubber-banding — limites suaves

Em um limite, resista progressivamente em vez de parar bruscamente. Uma parada brusca parece "congelada"; resistência contínua parece "responsivo, mas não há mais nada aqui". Aplique amortecimento que aumenta quanto mais longe do limite o usuário arrasta.

// Quanto mais longe do limite, menos o elemento segue — coisas reais desaceleram antes de parar
function rubberband(overshoot, dimension, constant = 0.55) {
  return (overshoot * dimension * constant) / (dimension + constant * Math.abs(overshoot));
}

10. Detalhes de design de gestos (a lista de verificação da 'sensação')

  • Toque: destaque ao tocar-para baixo (instantâneo), confirme ao tocar-para cima. Adicione ~10px de histerese/área de contato ao redor do alvo e permita cancelar arrastando para longe e de volta.
  • Arrastar/deslizar: exija um pequeno limite de movimento (histerese, ~10px) antes de se comprometer com uma direção, depois rastreie 1:1.
  • Detecte todos os gestos plausíveis em paralelo desde o primeiro movimento, e então cancele com confiança os perdedores quando a intenção estiver clara. Evite reconhecedores que apenas relatam um estado final (eventos do tipo swipeleft) — eles jogam fora o rastreamento contínuo que você precisa para o feedback.
  • Minimize os atrasos de desambiguação. A detecção de toque duplo inevitavelmente atrasa toques únicos; só pague esse custo onde o toque duplo realmente existe.

11. Suavidade no nível do quadro

A suavidade é sobre o que está nos quadros, não apenas a taxa de quadros.

  • Mantenha a mudança de posição por quadro abaixo do limite de percepção para evitar efeito estroboscópico.
  • Para movimento muito rápido, um sutil desfoque de movimento / esticamento codifica a velocidade e é melhor do que um traçado duro e nítido.
  • requestAnimationFrame é o relógio sincronizado com a exibição da web (a Apple usa CADisplayLink). Anime apenas propriedades amigáveis ao compositor — transform e opacity — e dê dica com will-change onde o movimento é iminente.

12. Materiais e profundidade — translucidez transmite hierarquia

A Apple usa materiais translúcidos como uma camada funcional flutuante que traz estrutura sem roubar o foco. Na web, aproxime com backdrop-filter.

  • Construa navegação/barras de ferramentas/folhas como camadas translúcidas (backdrop-filter: blur() + um fundo semitransparente) com conteúdo rolando por baixo — não barras opacas que consomem uma faixa fixa.
  • O peso do material codifica a hierarquia: materiais mais escuros/pesados separam regiões estruturais (barras laterais); materiais mais claros atraem a atenção para elementos interativos (botões). Nunca empilhe uma superfície translúcida clara sobre outra — a legibilidade colapsa.
  • Superfícies maiores devem parecer mais espessas: desfoque mais forte + uma sombra mais profunda do que pequenos chips. Considere sombra consciente do contexto — mais pesada sobre conteúdo ocupado/texto para separação, mais clara sobre fundos simples.
  • Escureça para focar, separe para manter o fluxo. Uma tarefa modal combina a superfície com um véu de escurecimento e empurra o fundo para trás/para baixo. Um painel paralelo e não bloqueador usa translucidez e deslocamento sem um véu para que o fluxo não seja interrompido. Para folhas empilhadas, escureça e empurre progressivamente cada camada pai.
  • A vibração mantém o texto legível sobre fundos variáveis. Sobre superfícies desfocadas/translúcidas, não use texto cinza plano — use contraste mais alto, peso ligeiramente maior e um pequeno aumento no espaçamento entre letras. Coloque cor em uma camada sólida, não no primeiro plano translúcido.
  • Efeitos de borda de rolagem, não divisores duros. Em vez de uma borda de 1px sob um cabeçalho fixo, desbote uma pequena máscara de desfoque/gradiente onde o conteúdo encontra o cromo flutuante — apenas onde a interface flutuante realmente se sobrepõe ao conteúdo.
  • Materialize, não apenas desvaneça. Para superfícies de vidro/desfoque, anime o raio de desfoque e a escala juntos na entrada/saída, para que a superfície pareça um material real chegando, em vez de uma simples transparência.
.toolbar {
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(20px) saturate(180%);
  border-top: 1px solid rgba(255, 255, 255, 0.4); /* borda superior brilhante = luz capturando o material */
}

13. Feedback multimodal — movimento + som + háptica

Três regras para combinar sentidos (de Designing Audio-Haptic Experiences):

  1. Causalidade — deve ser óbvio o que causou o feedback. Dispare-o no evento causal real (a alternância do botão, o item se encaixando no lugar) e corresponda seu caráter à fisicalidade da ação.
  2. Harmonia — o visual, o som e o háptico devem disparar no mesmo quadro. Latência entre eles destrói a ilusão. Não deixe uma…` }

Habilidades Relacionadas