O que Princípios de Design de Movimento faz?
Esta é a camada do bom gosto. Ela decide como algo deve se mover para que pareça polido e intencional, em vez de instável, flutuante ou barato. Ela não escreve o código que reproduz o movimento – uma vez que você tenha decidido a curva, o tempo e o arco, essa decisão é a entrada para um skill de direção/renderização (para vídeo de produto, entregue ao product-demo-director) ou para sua transição CSS/JS (para UI). Mantenha os dois trabalhos separados: este skill possui o julgamento; o skill de direção possui a orquestração e a mecânica.
Dispare em qualquer coisa sobre como o movimento parece: "deixar menos instável", "mais suave", "mais polido", "mais vivo", "a suavização está errada", "isto parece barato", "devo usar ease-in ou ease-out", "spring ou interpolate".
Quando usar um skill irmão
Este skill é apenas o julgamento de curva/tempo/arco. Adie quando a verdadeira pergunta for:
- Quais tomadas, ordem de cena ou uma lista de batidas → video-storyboard.
- Dirigir uma demonstração completa do produto – movimentos do cursor, capturas de tela, destaque de funcionalidades, a montagem da cena do início ao fim → product-demo-director. (Este skill produz a especificação de movimento que ele consome.)
- Animar texto ou letras – tipo que voa/se constrói/revela → kinetic-typography.
- Temporizar o movimento com uma batida, trilha sonora ou efeito sonoro → sound-and-music-sync.
- Cortar ou reenquadrar para uma plataforma (9:16, 1:1, áreas seguras) → social-video-formatter.
- Movimento de luz, exposição, brilho ou cor → motion-color-and-light.
Procedimento operacional
Diagnostique antes de prescrever. A maioria dos movimentos "instáveis" é um de quatro problemas nomeados, e cada um mapeia para uma correção específica abaixo. Trabalhe as etapas em ordem – a correção da suavização é inútil se o tempo estiver errado, e a correção do tempo é inútil se o elemento não tiver arco.
Etapa 1: Nomeie o que parece errado
Observe o movimento (ou a descrição dele) e classifique-o. Quase toda reclamação é uma destas:
- Linear / robótico – move-se a velocidade constante, para abruptamente. Sem suavização. Corrija na Etapa 2.
- Flutuante / mole – muito lento, ou suaviza na entrada e na saída quando deveria entrar rapidamente. Duração errada ou curva errada. Corrija na Etapa 2 e na Etapa 3.
- Instável / com travamentos – entra e sai na mesma velocidade, ou todas as propriedades animam na mesma linha do tempo plana, sem deslocamento. Faltam espaçamento e arco. Corrija na Etapa 3 e na Etapa 4.
- Morto / sem vida – tecnicamente correto, mas chato: sem antecipação, sem ultrapassagem, sem finalização. Faltam o arco e o movimento secundário. Corrija na Etapa 4 e na Etapa 5.
Escreva o diagnóstico em uma linha antes de tocar em qualquer coisa. "O modal está flutuante porque desaparece em 600ms com ease-in-out" é uma correção; "deixar mais bonito" não é.
Etapa 2: Escolha a curva de suavização
Suavização é a forma da velocidade ao longo do tempo do movimento. A curva carrega quase toda a qualidade percebida. Corresponda a curva ao que o elemento está fazendo:
- ease-out (início rápido, finalização lenta) – o padrão para coisas entrando e para qualquer coisa que o usuário acionou. Parece responsivo porque o movimento começa imediatamente, depois desacelera até o lugar. Use para: elementos aparecendo, menus suspensos abrindo, um botão tocado respondendo, conteúdo deslizando para dentro. Se não tiver certeza, use ease-out.
- ease-in (início lento, saída rápida) – para coisas saindo. O elemento acelera para fora da tela. Usado sozinho em uma entrada parece lento e atrasado, que é a causa nº 1 de "flutuante". Use para: dispensas, fechamentos, saídas.
- ease-in-out (lento, rápido, lento) – para mover algo já na tela de A para B: um cartão sendo reordenado, um carrossel avançando, um botão deslizante alternando. Ambas as extremidades estão ancoradas, então suavizar ambas as extremidades parece controlado. Não use para entradas – o início lento mata a responsividade.
- spring (física: massa, rigidez, amortecimento – ultrapassa e estabiliza) – para movimento que deve parecer vivo e físico: um modal surgindo, um botão de alternância, um botão de curtir, uma notificação caindo. A ligeira ultrapassagem é o que parece "vivo". Ajuste o amortecimento para personalidade: amortecimento menor = mais saltitante e divertido, amortecimento maior = mais firme e corporativo.
A decisão spring() vs interpolate() (quando você recorre a cada um no código) está na Barra de qualidade e no artefato executável abaixo. A versão resumida: spring para transformações físicas/vivas, interpolate para valores precisos e cronometrados como fades de opacidade, cor e barras de progresso.
Etapa 3: Defina o tempo e o espaçamento
Tempo é a duração total. Espaçamento é como a distância é distribuída ao longo dessa duração – espaçamento é a suavização tornada literal (um ease-out são quadros agrupados no final). Duas regras:
- A duração escala com a distância e o tamanho, não com o gosto. Um elemento pequeno se movendo uma curta distância deve ser rápido (UI: ~150–250ms). Um elemento grande ou um longo percurso precisa de mais tempo (~300–500ms) ou teletransporta. Movimento grande em tela cheia / hero em vídeo pode ser mais longo. Mesmo movimento, distância maior → duração maior.
- Entrada e saída não são simétricas. Saídas devem ser mais rápidas que entradas (~0,7–0,8x) – o usuário terminou com o elemento, então tire-o do caminho. Durações iguais de entrada/saída são uma fonte clássica de "instável".
Para vídeo de produto, converta para quadros assim que sair deste skill: quadros = round(segundos * fps). Essas contagens de quadros são a entrada literal que você entrega ao product-demo-director (que as transforma no plano de cena cronometrado).
Etapa 4: Construa o arco antecipação → ação → finalização
Movimento real raramente é um único movimento. O movimento mais rico e "vivo" tem três batidas:
- Antecipação – um pequeno movimento de preparação na direção oposta antes do movimento principal (um botão afunda para dentro ligeiramente antes de surgir, um cartão puxa para trás antes de deslizar para fora). Ele prepara o olho e faz a ação parecer intencional. Mantenha pequeno e rápido; muito parece um defeito.
- Ação – o movimento principal, carregando a suavização da Etapa 2 e a duração da Etapa 3. É aqui que o espaçamento vive.
- Finalização – o elemento estabiliza além do seu alvo e volta (a ultrapassagem da mola), e quaisquer elementos anexados/secundários ficam ligeiramente atrás do líder (um rótulo alcançando o cartão em que está). Isso é o que vende peso e vida.
Nem toda microinteração precisa de todos os três – uma dica de ferramenta de 150ms é apenas ação. Mas quando algo parece "morto", quase sempre está faltando antecipação ou finalização. Adicione o arco antes de adicionar floreios.
Etapa 5: Aplique os princípios da Disney relevantes
Os 12 princípios de animação da Disney se mapeiam diretamente para UI e movimento de produto. Você não aplica todos os doze; você recorre aos poucos que corrigem o problema diagnosticado. O mapeamento completo está em references/twelve-principles. Os de alto impacto:
- Slow in & slow out → suavização (Etapa 2). A alavanca de qualidade mais importante.
- Anticipation → a preparação (Etapa 4).
- Follow-through & overlapping action → ultrapassagem + elementos secundários atrasados (Etapa 4). A diferença entre "correto" e "vivo".
- Timing → duração e espaçamento (Etapa 3).
- Squash & stretch → escala sutil no pressionamento/impacto para implicar massa; em UI, mantenha alguns por cento ou parece um brinquedo.
- Staging → mova uma coisa de cada vez para que o olho saiba onde olhar; nunca anime seis coisas ao mesmo tempo na mesma curva.
- Secondary action – um pequeno movimento de suporte (uma sombra se aprofundando enquanto um cartão levanta) que reforça o principal sem competir.
- Exaggeration → empurre a pose chave ligeiramente além do realista; contido em UI, mais livre em um vídeo de produto impactante.
Etapa 6: Entregue a especificação
Preencha o modelo de especificação de movimento abaixo – curva, duração (e quadros), as batidas do arco e a chamada spring-vs-interpolate por propriedade. Essa especificação preenchida é o artefato de entrega: para uma cena de vídeo de produto vai diretamente para o product-demo-director; para UI torna-se seus valores de transição/keyframe. Combine com motion-color-and-light se a cena também precisar de movimento de luz/exposição, kinetic-typography se o texto estiver animando e sound-and-music-sync se o tempo precisar coincidir com uma batida.
Barra de qualidade
O movimento é A+ somente quando todos estes itens são verdadeiros:
- O diagnóstico é nomeado (linear / flutuante / instável / morto), e cada mudança remete a ele. Nenhum "deixou mais bonito" sem uma razão.
- Entradas usam ease-out, saídas usam ease-in, movimentos na tela A→B usam ease-in-out, movimentos vivos/físicos usam spring. Nenhum movimento linear bruto é enviado exceto loops deliberados de velocidade constante (um spinner, um letreiro).
- A duração escala com a distância/tamanho e a saída é mais rápida que a entrada.
- A chamada
spring()vsinterpolate()é explícita por propriedade: spring para transformações físicas (scale, translate, o pop/deslizamento/estabilização – você quer a ultrapassagem); interpolate para valores precisos cronometrados (fades de opacidade, cor, progresso, qualquer coisa onde a ultrapassagem pareceria errada). Um fade impulsionado por uma mola, ou um pop de logotipo impulsionado por interpolação linear, é um defeito. - Pelo menos um de antecipação ou finalização está presente no movimento principal / de assinatura; movimento sem vida está exatamente faltando esses.
- Uma coisa lidera de cada vez (staging); as propriedades são deslocadas em vez de dispararem todas em uma linha do tempo plana.
- Curva, duração e contagens de quadros estão escritos e prontos para serem entregues ao product-demo-director ou a uma transição – este skill nunca deixa a decisão implícita.
NÃO FAÇA
- NÃO envie suavização linear para entradas ou saídas – é o padrão robótico e parece inacabado. Velocidade constante é apenas para loops intencionais.
- NÃO use ease-in em uma entrada ou ease-out em uma saída – isso é a sensação flutuante/lenta invertida. Entradas usam ease-out, saídas usam ease-in.
- NÃO use durações de entrada e saída iguais; saídas devem ser ~0,7–0,8x mais rápidas.
- NÃO conduza um fade, cor ou barra de progresso com uma mola – a ultrapassagem faz os valores ultrapassarem seu intervalo e piscarem. Use interpolate para valores cronometrados.
- NÃO conduza um pop/deslizamento/escala vivo com interpolação linear quando você quiser que pareça vivo – use uma mola para a ultrapassagem.
- NÃO anime muitas propriedades em uma linha do tempo plana; organize e desloque-as.
- NÃO exagere na antecipação ou ultrapassagem em UI – alguns pixels / alguns por cento. Grandes preparações e saltos parecem um defeito ou um brinquedo.
- NÃO planeje a ordem das tomadas ou monte a demonstração aqui – entregue a especificação para o product-demo-director; a ordem do storyboard é do video-storyboard.
Seletor de suavização & mola
Script Node.js autônomo. Salve como motion_pick.js e execute com node motion_pick.js. Edite o array requests para os elementos que você está animando; ele retorna a curva, uma duração dimensionada pela distância (ms e quadros), a duração da saída e a chamada spring-vs-interpolate. Sem dependências.
// Seletor de movimento. Edite `requests`, depois: node motion_pick.js
const fps = 30 // para vídeo de produto; UI ignora a coluna de quadros
// role: 'enter' | 'exit' | 'move' | 'lively'
// distancePx: quão longe ele viaja (orienta a duração). sizePx: tamanho aproximado do elemento.
const requests = [
{ name: 'Modal pop-in', role: 'lively', property: 'scale', distancePx: 0, sizePx: 600 },
{ name: 'Modal backdrop', role: 'enter', property: 'opacity', distancePx: 0, sizePx: 1920 },
{ name: 'Toast slide-in', role: 'enter', property: 'translate', distancePx: 320, sizePx: 360 },
{ name: 'Toast dismiss', role: 'exit', property: 'translate', distancePx: 320, sizePx: 360 },
{ name: 'Card reorder', role: 'move', property: 'translate', distancePx: 140, sizePx: 280 },
{ name: 'Progress fill', role: 'move', property: 'width', distancePx: 800, sizePx: 800 },
]
function curveFor(role) {
if (role === 'enter') return 'ease-out'
if (role === 'exit') return 'ease-in'
if (role === 'move') return 'ease-in-out'
return 'spring' // lively
}
// A duração escala com a distância percorrida e o tamanho do elemento. Base + inclinação, limitada.
function durationMs(role, distancePx, sizePx) {
const reach = Math.max(distancePx, sizePx * 0.4)
let ms = 140 + reach * 0.45
ms = Math.min(Math.max(ms, 140), 600)
if (role === 'exit') ms *= 0.75 // saídas são mais rápidas
return Math.round(ms)
}
// spring para transformações físicas; interpolate para valores cronometrados.
function driver(role, property) {
const physical = property === 'scale' || property === 'translate'
if (role === 'lively') return 'spring() // quer a ultrapassagem'
if (physical && role !== 'move') return 'spring() // físico, estabilização viva'
return 'interpolate() // preciso, cronometrado por quadro'
}
const pad = (s, n) => String(s).padEnd(n)
console.log(pad('ELEMENTO', 18), pad('CURVA', 12), pad('MS', 6), pad('QUADROS', 8), 'DRIVER')
for (const r of requests) {
const curve = curveFor(r.role)
const ms = durationMs(r.role, r.distancePx, r.sizePx)
const frames = Math.round((ms / 1000) * fps)
console.log(pad(r.name, 18), pad(curve, 12), pad(ms, 6), pad(frames, 8), driver(r.role, r.property))
}
Saída de exemplo para as solicitações acima:
ELEMENTO CURVA MS QUADROS DRIVER
Modal pop-in spring 140 4 spring() // quer a ultrapassagem
Modal backdrop ease-out 140 4 interpolate() // preciso, cronometrado por quadro
Toast slide-in ease-out 284 9 spring() // físico, estabilização viva
Toast dismiss ease-in 213 6 spring() // físico, estabilização viva
Card reorder ease-in-out 203 6 interpolate() // preciso, cronometrado por quadro
Progress fill ease-in-out 500 15 interpolate() // preciso, cronometrado por quadro
Referências
references/twelve-principles– Mapeamento completo dos 12 princípios da Disney para UI/vídeo.- product-demo-director – Consome esta especificação para a montagem da cena.
- video-storyboard – Para planejamento da ordem das tomadas/batidas.
- motion-color-and-light – Quando o movimento precisa coordenar com luz/cor.
- kinetic-typography – Quando texto está animando (títulos, letras).
- sound-and-music-sync – Quando o tempo deve coincidir com uma batida/trilha sonora.