Communitygithub.com

marvinmcv-svg/SCCS-Landing-page

A abordagem da Apple para design de interface e movimento físico e fluido, traduzida para a web. Use ao construir ou revisar interfaces orientadas a gestos, animações spring, 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 estilo Apple.

O que é SCCS-Landing-page?

Este skill encapsula os princípios de design de interface da Apple, extraídos de palestras como a WWDC 2018 *Designing Fluid Interfaces*, e os traduz para implementação prática na web com CSS, JavaScript e bibliotecas de animação spring como Motion e Framer Motion. Ele é ideal para desenvolvedores que desejam criar interfaces que pareçam extensões naturais do usuário, com foco em resposta instantânea, manipulação direta, interrompibilidade, projeção de momentum e uso de springs para substituir animações de duração fixa. O skill detalha como matar latência, rastrear gestos 1:1 com o ponteiro, projetar pontos de repouso baseados em velocidade, aplicar elasticidade suave e materiais translúcidos para hierarquia visual. Também aborda acessibilidade (movimento reduzido) e co-design de feedback multimodal. Compatível com qualquer framework web, ele fornece trechos de código CSS e JavaScript, mapeamentos de parâmetros de spring e uma checklist prática de design. Útil para revisões de UI, prototipagem de gestos ou refatoração de animações existentes para serem fluidas e responsivas.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/marvinmcv-svg/SCCS-Landing-page/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 esta habilidade for invocada 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, traduzidas 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 spring como Motion/Framer Motion).

O fio condutor: 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 invertida a qualquer instante. Molas (springs) são a ferramenta que torna tudo isso natural, pois são inerentemente interrompíveis e cientes da velocidade.

A Ideia Central

"Quando alinhamos a interface com a forma como pensamos e nos movemos, algo mágico acontece — ela deixa de parecer um computador e passa a ser uma extensão perfeita de nós."

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 penhasco". A resposta é a base sobre a qual todo o resto é construído.

  • Responda no pointer-down, não no release. Destaque um botão no instante em que é pressionado. Esperar pelo click/touch-up para mostrar feedback parece morto.
  • Seja vigilante em relação a cada latência. Audite debounces, timers artificiais, esperas de transição e o atraso de ~300ms do tap. 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 UI 1:1 com o ponteiro o tempo todo — nunca anime apenas quando o gesto for concluído.
/* O feedback vive no pressionamento, 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 ele agarrou. Ajustar ao centro do elemento ao agarrar quebra a ilusão imediatamente.

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

3. Interrompibilidade — o princípio mais importante

"O pensamento e o gesto acontecem em paralelo."

Toda animação deve ser interrompível e redirecionável a qualquer momento. Um usuário deve poder agarrar um elemento em movimento no meio do ar 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 de apresentação (atual), nunca do valor alvo. Na interrupção, leia a transformação ao vivo do elemento na tela e inicie a nova animação a partir daí. Começar a partir do valor lógico/alvo causa um salto visível.
  • Evite transições CSS e @keyframes para qualquer coisa orientada a gestos — eles não podem ser suavemente agarrados e invertidos no meio do movimento. Molas animam a partir do valor atual por padrão, que é exatamente o que a interrupção precisa.
  • Quando um gesto reverte, mescle a velocidade — não a corte abruptamente. Substituir uma animação por outra em uma reversão cria uma descontinuidade de velocidade, uma "parede de tijolos". Bibliotecas spring que carregam a velocidade através de um re-target evitam isso. (É o que as animações aditivas do iOS fazem nativamente; na web, escolha uma biblioteca spring que re-direcione a partir da velocidade atual.)
  • Decomponha o movimento 2D em molas X e Y independentes. 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 substituiu deliberadamente o trio de física (massa/rigidez/amortecimento) por dois parâmetros amigáveis ao designer. Pense nestes:

  • Razão de amortecimento — controla o overshoot. 1.0 = criticamente amortecido, sem oscilação, ajuste suave. < 1.0 = ultrapassa e oscila. Menor = mais saltitante.
  • Resposta — quão rápido 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 estabilização emerge dos parâmetros.

Padrões:

  • Comece a maioria das UI 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 flick, um arremesso, um release de arrasto). Overshoot em um menu que apenas apareceu parece errado; overshoot em um cartão que você lançou 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 spring bounce + duration mapeia de perto para amortecimento + resposta da Apple. Um estilo de casa seguro é usar molas com damping: 1.0 em todos os lugares por padrão; reserve a oscilação para interações físicas e impulsionadas por 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 flick precedeu
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });

5. Handoff 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 "fluido" de "bom".

Passe a velocidade de release do ponteiro como a velocidade inicial da mola. Algumas APIs spring 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 você geralmente 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 release. Use a velocidade para projetar a posição de repouso — exatamente como a desaceleração de rolagem — então ajuste para o alvo mais próximo desse ponto projetado. Isso é o que faz um flick parecer que arremessa 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 faz o handoff de velocidade (§5)

Nota: a fórmula de livro-texto de 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 boas bottom-sheets e carrosséis (Vaul, Embla).

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

"Se algo desaparece de uma maneira, esperamos que apareça de onde veio."

  • Entre e saia pelo mesmo caminho. Um painel que desliza da direita deve desaparecer para a direita. Entrar pela direita / sair por baixo parece desconectado e confuso.
  • Ancore 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 dos popovers que escalam a partir de seu acionador, não de seu centro.)
  • Espelhe o easing em transições reversíveis para que o caminho de saída corresponda ao caminho de retorno (use pontos de controle cúbico-bezier inversos para as duas direções).

8. Sugira na direção do gesto

Humanos predizem um estado final a partir de uma trajetória. O movimento intermediário deve 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 os quadros intermediários apontarem para o resultado, não apenas interpolem cegamente até ele.

9. Elasticidade (rubber-banding) — limites suaves

Em um limite, resista progressivamente em vez de parar abruptamente. Uma parada brusca é lida como "congelado"; resistência contínua é lida como "responsivo, mas não há mais nada aqui." Aplique amortecimento que aumenta quanto mais o usuário arrasta além do limite.

// Quanto mais além 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 checklist de "sensação")

  • Tap: destaque no touch-down (instantâneo), confirme no touch-up. Adicione ~10px de histerese/padding de acerto ao redor do alvo e permita cancelar arrastando para longe e voltando.
  • Arrasto/deslize: exija um pequeno limite de movimento (histerese, ~10px) antes de se comprometer com uma direção, então rastreie 1:1.
  • Detecte todos os gestos plausíveis em paralelo desde o primeiro movimento, então cancele com confiança os perdedores quando a intenção estiver clara. Evite reconhecedores que relatam apenas um estado final (eventos 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 simples; só pague esse custo onde o toque duplo realmente existe.

11. Suavidade no nível do quadro

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 borrão de movimento / estiramento codifica a velocidade e é melhor visualmente do que um traçado nítido e duro.
  • requestAnimationFrame é o relógio sincronizado com a tela da web (a Apple usa CADisplayLink). Anime apenas propriedades amigáveis ao compositor — transform e opacity — e sugira 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 navs/barras de ferramentas/folhas como camadas translúcidas (backdrop-filter: blur() + um fundo semitransparente) com conteúdo rolando abaixo — não barras opacas que consomem uma faixa fixa.
  • O peso do material codifica hierarquia: materiais mais escuros/mais 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: blur mais forte + sombra mais profunda do que pequenos chips. Considere sombra sensível ao contexto — mais pesada sobre conteúdo denso/ocupado para separação, mais clara sobre fundos simples.
  • Escureça para focar, separe para manter o fluxo. Uma tarefa modal emparelha a superfície com um véu de escurecimento e empurra o fundo para baixo. Um painel paralelo e não bloqueador usa translucidez e deslocamento sem um véu para que o fluxo não seja quebrado. Para folhas empilhadas, escureça progressivamente e empurre cada camada pai para trás.
  • 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 mais pesado e um pequeno aumento no espaçamento entre letras. Coloque a cor em uma camada sólida, não no primeiro plano translúcido.
  • Efeitos de borda de rolagem, não divisórias rígidas. Em vez de uma borda de 1px sob um cabeçalho fixo, desvaneça uma pequena máscara de blur/gradiente onde o conteúdo encontra o cromo flutuante — apenas onde a UI flutuante realmente se sobrepõe ao conteúdo.
  • Materialize, não apenas fade. Para superfícies de vidro/blur, anime o raio do blur e a escala juntos na entrada/saída, para que a superfície pareça um material real chegando, em vez de um simples fade de opacidade.
.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. Acione-o no evento causal real (a alternância do botão, o encaixe do item) e combine seu caráter com a fisicalidade da ação.
  2. Harmonia — o visual, o som e o háptico devem disparar no mesmo quadro. A latência entre eles destrói a ilusão. Não deixe uma

…

[truncado para tradução]

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Habilidades Relacionadas