Communitygithub.com

grahama1970/apple-design

Abordagem da Apple para design de interfaces e movimento físico e fluido, traduzido para a web. Use ao construir ou revisar interfaces orientadas por 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, contenção) por trás das interfaces estilo Apple.

O que é apple-design?

Este skill fornece um guia completo para implementar princípios de design de interface da Apple na web, baseado principalmente na palestra *Designing Fluid Interfaces* (WWDC 2018) e outras fontes da Apple. Ele abrange desde conceitos fundamentais como capacidade de resposta instantânea e manipulação direta até técnicas avançadas como interrompibilidade de animações, transferência de velocidade entre gestos e animações, projeção de momentum para determinar destinos de snaps baseados na velocidade do dedo do usuário, e uso de molas (springs) para animações naturais e interrompíveis. O skill detalha implementações práticas para CSS e JavaScript, incluindo manipulação de eventos de ponteiro, animações com bibliotecas como Motion/Framer Motion, e funções de rubber-banding para limites suaves. Também aborda materiais translúcidos com `backdrop-filter`, feedback multimodal (visual + som + háptico), e diretrizes de acessibilidade para movimento reduzido. É útil para desenvolvedores web que desejam criar interfaces com sensação nativa, fluida e responsiva, semelhante às experiências em iOS e macOS.

Funciona com~Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/grahama1970/agent-skills/tree/main/skills/apple-design

Perguntar na sua IA favorita

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

Documentação

Apple Design

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 — principalmente Designing Fluid Interfaces (WWDC 2018) — destilado e traduzido para a plataforma web (CSS, Pointer Events, requestAnimationFrame, bibliotecas de spring 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 adiante e pode ser agarrada e revertida a qualquer instante. As Springs 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 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 no meio do movimento. Tudo abaixo é uma maneira de se aproximar 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 tudo o mais é construído.

  • Responda no pointer-down, não na liberação. 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 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, slider 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

"O toque e o conteúdo devem se mover juntos."

Quando o usuário arrasta algo, deve permanecer grudado ao dedo — e respeitar o deslocamento de onde o agarrou. Prender 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 curto histórico de velocidade/posição (últimos eventos pointermove), não apenas o ponto atual — você precisará da velocidade na liberação.
el.addEventListener('pointerdown', (e) => {
  el.setPointerCapture(e.pointerId);
  const grabOffset = e.clientY - el.getBoundingClientRect().top; // respeita onde agarrou
  // ...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 voo e invertê-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, depois reabrir.

  • Nunca bloqueie a entrada durante uma transição.
  • Sempre anime a partir do valor presente (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 por gestos — elas não podem ser suavemente agarradas e revertidas no meio do voo. As Springs animam a partir do valor atual por padrão, que é exatamente o que a interrupção precisa.
  • Quando um gesto inverte, 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 spring que carregam velocidade através de um novo destino evitam isso. (É isso que as animações aditivas do iOS fazem nativamente; na web, escolha uma biblioteca de spring que redirecione a partir da velocidade atual.)
  • Decomponha o movimento 2D em molas independentes 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é-programada e de duração fixa não pode responder a novas entradas. Uma mola pode — novas entradas apenas mudam 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 da física (massa/rigidez/amortecimento) por dois parâmetros amigáveis ao designer. Pense nisso:

  • Taxa de amortecimento — controla o overshoot. 1.0 = criticamente amortecido, sem oscilação, estabilização suave. < 1.0 = ultrapassa e oscila. Menor = mais saltitante.
  • 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 em amortecimento 1.0 (criticamente amortecido) — gracioso e não distrativo.
  • Adicione oscilação (amortecimento ~0.8) apenas quando o próprio gesto carregou 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ê jogou 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 próximo ao amortecimento + resposta da Apple. Um estilo de casa seguro é damping: 1.0 molas em todos os lugares por padrão; reserve oscilação para interações físicas baseadas em 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 a 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 "fluido" de "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:

relativeVelocity = gestureVelocity / (targetValue − currentValue)

Exemplo: elemento em y=50, alvo y=150 (100px para ir), 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 encaixe no 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 encaixe no alvo mais próximo desse ponto projetado. Isso é o que faz um flick parecer que arremessa o elemento.

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

// decelerationRate ≈ 0.998 para sensação de rolagem normal; 0.99 para mais rápida
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: o v²/(2·decel) do livro de física 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 emergia 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 pela parte de baixo parece desconexo e confuso.
  • Ancore as interações à sua origem. Um menu, popover ou folha deve originar-se 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 escalando a partir de seu acionador, não de 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-bézier inversos para as duas direções).

8. Dica 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 interpole cegamente até ele.

9. Rubber-banding — limites suaves

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

  • Toque: destaque no touch-down (instantâneo), confirme no touch-up. Adicione ~10px de histerese/almofada de acerto ao redor do alvo e permita cancelar arrastando para longe e de volta.
  • 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 assim que a intenção estiver clara. Evite reconhecedores que relatam apenas um estado final (eventos do tipo swipeleft) — eles jogam fora o rastreamento contínuo necessário para 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 limite de percepção para evitar estroboscopia.
  • Para movimento muito rápido, um sutil desfoque de movimento / esticamento codifica 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 dê dicas 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 barras de navegação/barras de ferramentas/folhas 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.
  • 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 desmorona.
  • 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 movimentado/texto para separação, mais leve 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 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 quebrado. Para folhas empilhadas, escureça e empurre progressivamente cada camada pai.
  • 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 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 UI flutuante realmente sobrepõe o conteúdo.
  • Materialize, não apenas apareç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 seja lida como um material real chegando, em vez de um fade 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 pegando no 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 virando, o item encaixando no lugar) 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 transição CSS atrasar o áudio/háptico (API de Vibração).
  3. Utilidade — adicione feedback apenas onde ele ganha seu lugar. Reserve háptica/som para momentos significativos (sucesso, erro, confirmação, encaixe). Excesso de feedback treina os usuários a ignorar tudo.

14. Movimento reduzido e acessibilidade

Movimento reduzido não significa nenhum feedback

...[truncado para tradução]

Individual skills in this repo

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

grahama1970/acceptance-contract

Turn a client brief, zip bundle, directory, or single requirements file into a typed acceptance-contract bundle with extracted requirements, acceptance checks, open questions, an immutable-goal draft, and a create-report-backed decision report. Use when users say acceptance contract, brief to requirements, freeze the goal, create immutable goal, amend immutable goal, build a Battle requirements bundle, or extract requirements from this bundle.

grahama1970/agent-ecosystem

Canonical map and shared contracts for the agent-governance ecosystem: the pi.receipt_envelope.v1 boundary envelope, the component graph, and the rules for which component owns which schema. Use when wiring a skill or extension into the shared receipt world, when asking how shame, triage-error, tau, ask, project-watchdog, ops-herdr, ponytail, and Memory fit together, or when validating an envelope.

grahama1970/agentic-evals

Agentic evaluation of skills using multi-trial fixtures, deterministic command assertions, trajectory checks, safety constraints, and evidence-backed readiness scoring. Use when users ask for agentic evals, multi-trial skill evaluation, skill trajectory validation, or readiness scoring for a skill workflow.

grahama1970/agent-inbox

File-based inter-agent messaging with headless dispatch. Check inbox, send bugs/requests to other projects, automatically spawn headless agents to fix bugs, and track progress via task-monitor.

grahama1970/agents-registry

Generate and query the centralized agent identity registry. Scans .pi/agents/*/AGENTS.md, parses frontmatter, outputs agents-registry.json and optionally syncs to /memory for semantic search.

grahama1970/agent-status

Artifact-driven status surfaces for long-running project-agent work. Maintains status.json, events.jsonl, proof manifests, and a stale-aware STATUS.html so humans can tell where the agent is, what passed, what is still unproven, and what decision or action is next — without dashboard theater.

grahama1970/align

Round-based context alignment before execution. Use when the human, project agent, WebGPT, scillm, ask, dogpile, memory, or project-knowledge may each hold different facts about a task; especially before ambiguous design, infographic, product workflow, high-stakes implementation, plan-iterate, project-infographic, or multi-review work.

grahama1970/analytics

Flexible data science analytics for any dataset. Auto-discovers schema, recommends charts, exports to create-figure. Works with JSONL, JSON, CSV from any source.

grahama1970/analyze-chatterbox-emotions

Evaluate generated Chatterbox voice files as voice-quality artifacts: affect match, arousal/valence proxies, pause placement, intelligibility inputs, clipping, loudness, and discontinuity flags. Use when reviewing Chatterbox emotional tags, pauses, Turbo/base affect delivery, Persona Dream utterance renders, or whether generated speech matches an intended product-facing affect.

grahama1970/analyze-elf

Reverse-engineer features from ELF binaries. Extracts CLI commands, state machines, protocols, Zod schemas, and data models. Automatically generates a /create-walkthrough prosecution brief with Mermaid diagrams. Uses /treesitter for AST analysis of bundled JS/TS source.

grahama1970/animation-vocabulary

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.

grahama1970/anonymize-data

Anonymize supported CSV, JSON, UTF-8 text, and SQLite files using an explicit policy through the oai-trial project. Use for anonymize data, pseudonymize exports, redact policy literals, or discover and explicitly approve fuzzy name aliases. The skill is a thin CLI/Docker interface, not another engine.

grahama1970/anvil

Heavy-duty "No-Vibes" debugging and hardening orchestrator. Use this for complex, stubborn bugs where `review-code` has failed, or for "Red Teaming" (hardening) a codebase. Runs multiple agents in parallel (Thunderdome) using git worktree isolation.

grahama1970/argue

Multi-persona structured debate orchestrator. Personas research via /dogpile, consult colleagues via /ask, and argue toward nuanced synthesis on complex questions.

grahama1970/arxiv

Search arXiv for papers and extract knowledge into memory. Use `search` to find papers, `learn` to extract knowledge.

grahama1970/ask

Use when the user asks to query project memory, ask an oracle, use supported browser-backed reviewers, run Tau roundtable/single-handler workflows, ask Pi-native subagents from within Pi, run persona/deep-review workflows, generate image prompts, check OS/project health through composed skills, or run an ask DAG. This skill is the executable /ask runtime; do not replace it with an informal subagent, plain web search, or hand-written review; inside Pi, explicit Pi-native subagent targets are routed through the pi-subagents tool as an Ask target type.

grahama1970/assess

Step back and critically reassess project state. Use when asked to "assess", "step back", "fresh eyes", "check alignment", "sanity check", "health check", "prune documentation", or "evaluate what's working". Offers documentation pruning and doc-code alignment analysis. Offer to run after major changes (don't auto-run).

grahama1970/assistant

Shared GPT + classifier inference gateway for persona monitor tasks. Routes validation and classification through a 4-tier cascade: heuristic → classifier → local GPT → scillm.

grahama1970/assistant-lab

Self-improvement workbench for /assistant. All the tools needed to diagnose, train, evaluate, and promote models in a continuous loop. The "warm pond" where /assistant evolves its own inference stack.

grahama1970/batch-quality

Pre-flight validation and quality gates for batch LLM operations. ACTUALLY tests samples through LLM before burning tokens. Uses SPARTA contracts for DuckDB validation queries. Integrates with task-monitor for enforced quality gates.

Habilidades Relacionadas