Tokens de Movimento
Design System · Arrow DS · Dimensão 06 Movimento
Versão: 1.0 · Status: Validado
Âncora base: 200ms (duration-200) centro de gravidade do sistema
Depende de: Dimensões 01–05
Usado por: Todos os componentes de UI interativos, transições de layout, momentos expressivos
Princípios da Dimensão
Movimento é sentido não percebido.
Cor, tipografia e espaçamento são percebidos. Movimento é sentido. É a dimensão mais sensível de todas e é exatamente aí que os sistemas mediocres falham: tratam movimento como camada decorativa, quando ele é o produto respirando.
Intencional. Responsivo. Caloroso.
A Effecti precisa de um movimento que seja rápido sem ser ansioso, vivo sem ser teatral, e humano sem ser impreciso.
Funcional como regra, expressivo como exceção deliberada.
A maioria dos movimentos é utilitária e invisível. Em momentos específicos um sucesso, uma conquista, um onboarding o produto respira com mais personalidade.
As Três Tensões Resolvidas
Tensão 01 Velocidade vs. Presença
Resolução: o sistema mora no rápido mas não no imediato. Teto de duração baixo, base ainda mais baixa.
Tensão 02 Funcional vs. Expressivo
Resolução: funcional como regra, expressivo como exceção deliberada.
Tensão 03 Física vs. Matemática
Resolução: cubic-bezier com curvas calibradas para humanidade. Sem springs. Controle total, portabilidade total.
Fundação
| Propriedade | Valor | Descrição |
|---|---|---|
| Centro de gravidade | 200ms | A duração que o usuário sentirá como resposta natural |
| Teto absoluto | 500ms | Nenhum movimento na Effecti dura mais que isso |
| Método de curva | cubic-bezier exclusivo | Sem springs portabilidade e controle totais |
| Propriedades animadas | Declaradas explicitamente | all nunca é animado |
Primitivos de Duração
| Token Primitivo | Valor | Percepção |
|---|---|---|
duration-0 | 0ms | Imediato sem transição |
duration-75 | 75ms | Quase imperceptível |
duration-150 | 150ms | Rápido resposta limpa |
duration-200 | 200ms | Fluido o centro do sistema |
duration-300 | 300ms | Deliberado movimento com peso |
duration-400 | 400ms | Expansivo espaço para respirar |
duration-500 | 500ms | Expressivo reservado para momentos |
css
:root {
--duration-0: 0ms;
--duration-75: 75ms;
--duration-150: 150ms;
--duration-200: 200ms;
--duration-300: 300ms;
--duration-400: 400ms;
--duration-500: 500ms;
}
duration-200é o centro de gravidade do sistema. Rápido o suficiente para não frustrar. Presente o suficiente para ser caloroso.
Tokens Semânticos
Categoria: Duração motion.duration
motion.duration.instant
| Token | Primitivo | Valor | Intenção |
|---|---|---|---|
motion.duration.instant | duration-0 | 0ms | Estados que não devem ser percebidos como transição |
motion.duration.interaction
| Token | Primitivo | Valor | Intenção |
|---|---|---|---|
motion.duration.interaction.fast | duration-75 | 75ms | Hover, pressed, toggle feedback imediato |
motion.duration.interaction.base | duration-150 | 150ms | Check, radio, switch mudança de estado |
motion.duration.interaction.comfortable | duration-200 | 200ms | Botão com ícone, chip select resposta com presença |
css
--motion-duration-interaction-fast: var(--duration-75);
--motion-duration-interaction-base: var(--duration-150);
--motion-duration-interaction-comfortable: var(--duration-200);motion.duration.transition
| Token | Primitivo | Valor | Intenção |
|---|---|---|---|
motion.duration.transition.enter | duration-200 | 200ms | Entrada de elementos aparecem com calor |
motion.duration.transition.exit | duration-150 | 150ms | Saída de elementos saem mais rápido que entram |
motion.duration.transition.layout | duration-300 | 300ms | Reorganização de layout, expansão de accordion |
motion.duration.transition.page | duration-300 | 300ms | Transição entre páginas ou views |
css
--motion-duration-transition-enter: var(--duration-200);
--motion-duration-transition-exit: var(--duration-150);
--motion-duration-transition-layout: var(--duration-300);
--motion-duration-transition-page: var(--duration-300);motion.duration.expressive
| Token | Primitivo | Valor | Intenção |
|---|---|---|---|
motion.duration.expressive.feedback | duration-400 | 400ms | Confirmação de sucesso, erro crítico |
motion.duration.expressive.celebration | duration-500 | 500ms | Onboarding, conquista, primeiro acesso |
css
--motion-duration-expressive-feedback: var(--duration-400);
--motion-duration-expressive-celebration: var(--duration-500);Categoria: Easing motion.easing
| Token semântico | Curva | Comportamento | Uso |
|---|---|---|---|
motion.easing.productive | cubic-bezier(0.2, 0, 0, 1) | Entrada rápida, pouso suave | Interações utilitárias cotidiano do sistema |
motion.easing.enter | cubic-bezier(0, 0, 0.2, 1) | Velocidade máxima no início, desaceleração total | Elementos que aparecem |
motion.easing.exit | cubic-bezier(0.4, 0, 1, 1) | Saída suave com aceleração progressiva | Elementos que saem |
motion.easing.expressive | cubic-bezier(0.34, 1.56, 0.64, 1) | Overshoot controlado | Momentos de significado |
css
--motion-easing-productive: cubic-bezier(0.2, 0, 0, 1);
--motion-easing-enter: cubic-bezier(0, 0, 0.2, 1);
--motion-easing-exit: cubic-bezier(0.4, 0, 1, 1);
--motion-easing-expressive: cubic-bezier(0.34, 1.56, 0.64, 1);Categoria: Padrões motion.pattern
Regra global de padrões: cada padrão declara explicitamente quais propriedades CSS anima.
transition: allnão existe no sistema Arrow DS.
motion.pattern.feedback
| Token | Duration | Easing | Propriedades CSS |
|---|---|---|---|
motion.pattern.feedback.hover | duration-75 | productive | background-color, border-color |
motion.pattern.feedback.press | duration-75 | productive | transform, background-color |
motion.pattern.feedback.focus | duration-150 | productive | outline, box-shadow |
motion.pattern.feedback.toggle | duration-150 | productive | background-color, transform |
css
.motion-feedback-hover {
transition-property: background-color, border-color;
transition-duration: var(--duration-75);
transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
.motion-feedback-press {
transition-property: transform, background-color;
transition-duration: var(--duration-75);
transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
.motion-feedback-focus {
transition-property: outline, box-shadow;
transition-duration: var(--duration-150);
transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
.motion-feedback-toggle {
transition-property: background-color, transform;
transition-duration: var(--duration-150);
transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}motion.pattern.enter
| Token | Duration | Easing | Estado inicial |
|---|---|---|---|
motion.pattern.enter.fade | duration-200 | enter | opacity: 0 |
motion.pattern.enter.slide.up | duration-200 | enter | opacity: 0; transform: translateY(8px) |
motion.pattern.enter.slide.down | duration-200 | enter | opacity: 0; transform: translateY(-8px) |
motion.pattern.enter.scale | duration-200 | enter | opacity: 0; transform: scale(0.95) |
Combinações recomendadas
motion.pattern.enter.fade → conteúdo assíncrono, tab content, lazy load
motion.pattern.enter.slide.up → dropdown, select aberto, combobox, popover
motion.pattern.enter.slide.down → toast, snackbar, banner de notificação
motion.pattern.enter.scale → modal, dialog, drawermotion.pattern.exit
| Token | Duration | Easing | Estado final |
|---|---|---|---|
motion.pattern.exit.fade | duration-150 | exit | opacity: 0; visibility: hidden |
motion.pattern.exit.slide.up | duration-150 | exit | opacity: 0; transform: translateY(-8px) |
motion.pattern.exit.slide.down | duration-150 | exit | opacity: 0; transform: translateY(8px) |
motion.pattern.exit.scale | duration-150 | exit | opacity: 0; transform: scale(0.95) |
motion.pattern.layout
| Token | Duration | Easing | Propriedades CSS |
|---|---|---|---|
motion.pattern.layout.expand | duration-300 | productive | height, opacity |
motion.pattern.layout.collapse | duration-300 | productive | height, opacity |
motion.pattern.layout.reorder | duration-300 | productive | transform |
motion.pattern.layout.page | duration-300 | enter | opacity, transform |
motion.pattern.expressive
| Token | Duration | Easing | Propriedades CSS |
|---|---|---|---|
motion.pattern.expressive.success | duration-400 | expressive | opacity, transform |
motion.pattern.expressive.error | duration-400 | productive | transform shake horizontal controlado |
motion.pattern.expressive.celebration | duration-500 | expressive | opacity, transform |
css
@keyframes motion-success {
from { opacity: 0; transform: scale(0.8); }
to { opacity: 1; transform: scale(1); }
}
@keyframes motion-error-shake {
0% { transform: translateX(0); }
20% { transform: translateX(-6px); }
40% { transform: translateX(6px); }
60% { transform: translateX(-4px); }
80% { transform: translateX(4px); }
100% { transform: translateX(0); }
}
@keyframes motion-celebration {
from { opacity: 0; transform: scale(0.6) translateY(16px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}Regras Globais do Sistema
Hierarquia de Camadas
| Camada | Padrões | Frequência | Easing permitido |
|---|---|---|---|
| Utilitária | feedback.* · enter.* · exit.* · layout.* | Alta cotidiano do produto | productive · enter · exit |
| Expressiva | expressive.* | Baixa momentos de significado | productive · expressive |
Regra crítica:
motion.easing.expressiveé a única curva com overshoot do sistema. Nenhum componente utilitário acessa essa curva.
Assimetria Enter/Exit Sistêmica e Imutável
| Direção | Duração | Razão |
|---|---|---|
| Entrada | duration-200 | Elemento que entra precisa de presença caloroso |
| Saída | duration-150 | Elemento que sai precisa de agilidade libera espaço |
O que nunca pode ser animado
| Proibido | Razão |
|---|---|
| Conteúdo textual denso (tabelas, listas longas) | Ruído cognitivo |
| Texto de mensagem de erro | Erro é urgente aparece instantaneamente |
| Loops infinitos em tela estável | Distração em contexto operacional |
top, left, right, bottom em animações | Causa reflow usar transform: translate() |
width em padrões de layout | Causa layout thrashing |
O que nunca fazer
| Proibido | Alternativa correta |
|---|---|
transition: all | Declarar propriedades explícitas |
transition-duration: 300ms direto no componente | var(--motion-duration-transition-layout) |
cubic-bezier(0.34,1.56,0.64,1) em botão | var(--motion-easing-productive) |
animation-duration: 600ms | Acima do teto requerer decisão explícita |
motion.easing.expressive em dropdown, input, card | Exclusivo para motion.pattern.expressive.* |
Acessibilidade prefers-reduced-motion
Todo token de movimento do sistema tem um equivalente reduzido declarado. Sem exceção.
Três camadas de substituição:
- Camada 01 Feedback: acontece instantaneamente, sem transição
- Camada 02 Enter/Exit: fade ultra-rápido de 75ms sem movimento espacial
- Camada 03 Expressivo: desativado completamente
css
@media (prefers-reduced-motion: reduce) {
.motion-feedback-hover,
.motion-feedback-press,
.motion-feedback-focus,
.motion-feedback-toggle {
transition-duration: 0ms;
}
.motion-enter-fade,
.motion-enter-slide-up,
.motion-enter-slide-down,
.motion-enter-scale,
.motion-exit-fade,
.motion-exit-slide-up,
.motion-exit-slide-down,
.motion-exit-scale {
transition-property: opacity;
transition-duration: 75ms;
transform: none !important;
}
.motion-expressive-success,
.motion-expressive-error,
.motion-expressive-celebration {
animation: none;
transition: none;
}
}Decisões Estratégicas Registradas
duration-200 como centro de gravidade do sistema
A maioria das interações da Effecti vive aqui. Qualquer novo componente que não sabe qual duração usar começa por aqui.
Saída mais rápida que entrada assimetria sistêmicaexit usa duration-150; enter usa duration-200. Assimetria intencional, sistêmica e imutável.
duration-500 como teto absoluto
Nada na Effecti dura mais que 500ms. Qualquer movimento acima exige justificativa documentada.
all nunca é animado
Toda propriedade CSS animada é declarada explicitamente. transition: all não existe no sistema.
Erro não usa expressive
Erro é urgente. A curva expressive com overshoot celebra não alerta. error usa productive com shake horizontal.
cubic-bezier exclusivo sem springs
Portabilidade para qualquer plataforma é inegociável. Springs introduzem complexidade sem ganho proporcional.
Exemplos de Uso
Escala de duração — primitivos comparados
duration-150 → duration-500 — distância perceptual entre os stops (loop)
150ms
Rápido — resposta limpa
200ms ⚓
Centro de gravidade
300ms
Deliberado — com peso
500ms
Expressivo — teto absoluto
Curvas de easing — comparação simultânea
productive · enter · exit · expressive — mesma distância e duração
productive
enter
exit
expressive
Feedback de interação — hover e pressed
motion.pattern.feedback — passe o mouse e clique (duration-75 · productive)
Arquivos de Output Dimensão 06
| Arquivo | Formato | Conteúdo |
|---|---|---|
effecti_motion_tokens_v1.md | Markdown | Documentação completa |
effecti_tokens_motion.css | CSS | Primitivos + semânticos + padrões + prefers-reduced-motion |
Effecti Programa de Governança de Design System · Dimensão 06 · v1.0