Communitygithub.com

RevanthThota55/FreeFrame-Studio

A 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/painéis, 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, contenção) por trás das interfaces estilo Apple.

O que é FreeFrame-Studio?

Este skill traduz os princípios de design de interface da Apple, extraídos de palestras do WWDC como *Designing Fluid Interfaces* (2018), para o contexto da web usando CSS, Pointer Events, `requestAnimationFrame` e bibliotecas de mola como Motion/Framer Motion. Ele se concentra em criar interfaces que parecem extensões do usuário, com foco em resposta instantânea, manipulação direta 1:1, interrompibilidade total de animações, uso de molas em vez de animações de duração fixa, transferência de velocidade do gesto para a animação, projeção de momentum para posições de descanso realistas e consistência espacial. O skill é útil para desenvolvedores que desejam implementar interações fluidas, como painéis deslizantes, arrastos, carrosséis e gestos, com o mesmo nível de polimento e naturalidade encontrado em sistemas Apple. Suporta plataformas web modernas e enfatiza acessibilidade com diretrizes para movimento reduzido.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/RevanthThota55/FreeFrame-Studio/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 na 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 passam a parecer uma extensão de você. Este conhecimento vem das palestras de design da WWDC da Apple — principalmente Designing Fluid Interfaces (WWDC 2018) — destiladas e traduzidas para a plataforma web (CSS, Pointer Events, requestAnimationFrame, bibliotecas de mola como Motion/Framer Motion).

A linha condutora: 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 ao modo 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."

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 forma de chegar mais perto disso.

A Apple enquadra o design como serviço para 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 "despenca." 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 click/toque para mostrar feedback parece morto.
  • Esteja atento a cada latência. Audite debounces, timers artificiais, esperas de transição e o atraso de ~300ms do toque. 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 durante todo o caminho — nunca anime apenas quando o gesto é 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 o 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.
  • Rastreie um breve histórico de velocidade/posição (ú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 agarrou
  // ...rastreia posição + histórico de 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 ser capaz de agarrar um elemento em movimento durante o voo e revertê-lo sem esperar a animação terminar. Um modal fechando que 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. Ao interromper, leia a transformação ao vivo do elemento na tela e inicie a nova animação a partir daí. Começar pelo valor lógico/alvo causa um salto visível.
  • Evite transições CSS e @keyframes para qualquer coisa orientada por gestos — eles não podem ser suavemente agarrados e revertidos durante o voo. Molas animam a partir do valor atual por padrão, que é exatamente o que a interrupção precisa.
  • Quando um gesto reverte, combine 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. (Isto é o que as animações aditivas do iOS fazem nativamente; na web, escolha uma biblioteca de mola que redefina o alvo 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é-programada 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 um usuário possa tocar.

A Apple substituiu deliberadamente o trio de parâmetros físicos (massa/rigidez/amortecimento) por dois parâmetros amigáveis ao designer. Pense nestes:

  • Razão de amortecimento — controla o overshoot. 1.0 = amortecimento crítico, sem quique, estabilização suave. < 1.0 = overshoot e oscila. Menor = mais elástico.
  • Resposta — a rapidez com que 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 da UI com amortecimento 1.0 (amortecimento crítico) — gracioso e não perturbador.
  • Adicione quique (amortecimento ~0.8) apenas quando o gesto em si carregava momentum (um flick, um arremesso, uma liberação 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 / painel0.80.3

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

import { animate } from 'motion';

// Padrão com amortecimento crítico (sem overshoot)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });

// Interação com momentum — um pouco de quique, apenas porque um flick 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 "ok."

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 a percorrer), dedo movendo-se 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 ao limite mais próximo a partir do ponto de liberação. Use a velocidade para projetar a posição de descanso — exatamente como a desaceleração de rolagem — e então ajuste ao alvo mais próximo daquele ponto projetado. É isso 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 normal de rolagem; 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 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 surja de onde veio."

  • Entre e saia pelo mesmo caminho. Um painel que desliza da direita deve ser dispensado para a direita. Entrar pela direita / sair por baixo parece desconectado e confuso.
  • Ancore as interações à sua origem. Um menu, popover ou painel 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 escalonam a partir de seu acionador, não de seu centro.)
  • Espelhe a easing 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. Dê dicas 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 com que os quadros intermediários apontem para o resultado, não apenas interpolem cegamente até ele.

9. Elasticidade — limites suaves

Em um limite, resista progressivamente em vez de parar bruscamente. Uma parada brusca parece "congelada"; a resistência contínua parece "responsiva, 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 lista de verificação da "sensação")

  • Toque: destaque ao pressionar (instantâneo), confirme ao soltar. Adicione ~10px de histerese/padding de acerto ao redor do alvo e permita cancelar arrastando para longe e voltando.
  • Arrastar/deslizar: 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 assim que a intenção estiver clara. Evite reconhecedores que relatam apenas um estado final (eventos do tipo swipeleft) — eles descartam o rastreamento contínuo necessário para o feedback.
  • Minimize 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 posicional por quadro abaixo do limiar de percepção para evitar estroboscopia.
  • Para movimento muito rápido, um sutil desfoque de movimento / esticamento codifica a velocidade e é mais legível do que um traço 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/painéis como camadas translúcidas (backdrop-filter: blur() + um fundo semi-transparente) com conteúdo rolando por baixo — não barras opacas que consomem uma faixa fixa.
  • 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 desaba.
  • Superfícies maiores devem parecer mais espessas: desfoque mais forte + uma sombra mais profunda do que pequenos chips. Considere sombra sensível ao contexto — mais pesada sobre conteúdo/texto movimentado para separação, mais leve sobre fundos simples.
  • Escureça para focar, separe para manter o fluxo. Um modal de tarefa emparelha a superfície com um escurecimento de fundo e empurra o fundo para trás/para baixo. Um painel paralelo e não bloqueador usa translucidez e deslocamento sem um escurecimento para que o fluxo não seja interrompido. Para painéis empilhados, 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 liso — 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 divisores duros. Em vez de uma borda de 1px sob um cabeçalho fixo, desvaneça um pequeno gradiente/máscara de desfoque onde o conteúdo encontra o cromo flutuante — apenas onde a UI flutuante realmente sobrepõe o conteúdo.
  • Materialize, não apenas desvaneça. Para superfícies de vidro/desfoque, anime o raio do desfoque e a escala juntos ao entrar/sair, para que a superfície seja lida como um material real chegando, em vez de um desvanecimento de opacidade simples.
.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 que um

…

[truncado para tradução]

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

RevanthThota55/FreeFrame-Studio

Build an animation from scratch, making the decisions in the order that determines whether it feels right — should it animate at all, what purpose, which tool, which properties, which curve and duration, how it interrupts, how it exits. Writes the implementation. Use when asked to animate something, add motion, make a component feel alive, or build a transition. For critiquing existing motion use review-animations; for auditing a whole codebase use improve-animations.

RevanthThota55/FreeFrame-Studio

Keep web animations inside the frame budget — animate composite-only properties, keep motion off the main thread when the page is busy, and find the cause when an animation drops frames. Covers the layout/paint/composite pipeline, cheaper property swaps, CSS vs WAAPI vs requestAnimationFrame, Framer Motion's hardware-accelerated path, React re-rendering per frame, inherited CSS variable recalculation, blur cost, and when `will-change` actually helps. Use when an animation is janky, choppy, stutters, or drops frames; when choosing which property to animate; when deciding between CSS and JS animation on performance grounds; or when reaching for `will-change` or GPU layers. For choosing easing, duration, or whether to animate at all use animate; for reviewing motion as a whole use review-animations.

RevanthThota55/FreeFrame-Studio

Reverse-lookup glossary that turns a vague description of a web animation or motion effect into its exact term ("the bouncy thing when a popover opens" → Pop in; "the iOS rubber-band scroll" → Rubber-banding). Use when the user asks "what's it called when…", or describes a motion effect without knowing its name and wants the right word to prompt an AI or designer with. For naming an effect, not designing or building one.

Habilidades Relacionadas