Communitygithub.com

nkurunziza-saddy/motion

Construye animaciones para la interfaz de producto en la web. Decide si algo debe moverse, por qué, qué herramienta usar (CSS transition, WAAPI, Motion, spring), qué propiedades, curva, duración, interrupción, salida y ruta de movimiento reducido, y escribe el código. También cubre escalonamiento y coreografía, gestos (arrastrar, deslizar, paneles), tokens de animación y rendimiento.

¿Qué es motion?

Esta habilidad define el proceso completo para construir animaciones en interfaces de producto web. Comienza con una decisión fundamental: determinar si un elemento debe moverse o no, basándose en la frecuencia con la que el usuario lo ve. Si el movimiento es necesario, guía al desarrollador a través de una serie de pasos estructurados: nombrar el propósito (espacial, estado, retroalimentación, continuidad o explicación), seleccionar la herramienta más eficiente (CSS transition, WAAPI, Motion, etc.), elegir las propiedades correctas (transform, opacity, filter), y emparejar la curva y duración adecuadas según el uso. También aborda casos complejos como interrupciones, animaciones de salida, movimiento reducido, coreografía de múltiples elementos y gestos como arrastrar o deslizar. La habilidad está diseñada para plataformas como Claude Code y Cursor, y se apoya en documentos de referencia (tokens, recetas, gestos, rendimiento) que se cargan bajo demanda. El resultado es un código de animación optimizado, accesible y de alto rendimiento que evita errores comunes como `transition: all`, animaciones en elementos de alta frecuencia, o la falta de soporte para `prefers-reduced-motion`.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/nkurunziza-saddy/hmm-interfaces/tree/HEAD/motion

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Animación (Motion)

Esta habilidad construye animaciones. Extiende la sección de animación de product-ui/references/values.md, que contiene los números acordados (curvas de easing, escala al presionar, rebote, escalonamiento, tabla de duraciones, duraciones de toast y diseño, distancias de viaje, relación salida-entrada). Esos números no se repiten aquí; esta habilidad añade el orden de las decisiones, los tokens, las recetas y los modos de fallo.

Antes de cualquier decisión, aplica product-ui §1 (el diario de gusto y precedencia) y §5 (qué habilidad es dueña de qué).

El orden de las decisiones

Recorre esto de arriba a abajo. Cada paso puede finalizar el trabajo. Cero líneas de animación es un resultado válido, y así lo indicas.

1. ¿Debería moverse? El filtro de frecuencia

Pregunta cuántas veces al día un usuario ve esto. Los niveles están en values.md. En la práctica:

  • Iniciado por teclado, o visto 100+ veces al día: sin movimiento. Por qué: el movimiento repetido se convierte en retraso.
  • Visto decenas de veces al día (hover, cambio de pestaña, selección de fila): ninguno, o un cambio de color instantáneo.
  • Los datos que el usuario está leyendo o sobre los que actúa (un número en una tabla, un gráfico en un panel en vivo) nunca se mueven por estilo. Por qué: el movimiento desvía la atención de lo que se está leyendo.
  • Si el filtro dice no, escribe ninguna animación. Indica qué nivel alcanzó, y ofrece la alternativa estática (un cambio de estado instantáneo).

2. Nombra el propósito

Elige una palabra: espacial (de dónde vino o a dónde fue), estado (esto cambió), retroalimentación (te escuché), continuidad (evita un salto), explicación (solo momentos raros). Si no puedes nombrarla, detente. Por qué: "se ve bonito" en un elemento frecuente es la principal fuente de interfaz que se siente lenta.

3. Elige la herramienta: la más barata que funcione

NecesidadHerramienta
Un estado alternado por clase, atributo, hover o presionarCSS transition
Entrada desde display: none, popover o diálogo@starting-style + transition-behavior: allow-discrete
Una secuencia única, escalonamiento, o animación que debe ejecutarse mientras la página está ocupadaCSS @keyframes
JS decide cuándo; necesitas cancelar, revertir, finished, o FLIPWAAPI el.animate()
Springs, transferencia de velocidad, salida de un nodo React que se desmonta, diseño compartidoMotion (motion/react)

Si la cosa es un componente completo (menú, toast, cajón), usa una librería que maneje el foco, y pregunta pick-library. Nunca instales Motion para un fade. Por qué: CSS se ejecuta fuera del hilo principal y no cuesta nada en el bundle.

4. Propiedades

  • Anima transform y opacity; filter solo para un desenfoque de intercambio ≤ 2px. Nombra cada propiedad; nunca transition: all.
  • Cambios de altura y diseño: consulta references/recipes.md (filas de grid, FLIP). Nunca animes width, top, left o margin para mover algo. Por qué: cada una fuerza el diseño en cada fotograma.
  • Nunca animes box-shadow. Desvanece la opacidad de un pseudo-elemento en su lugar.
  • Los porcentajes de translate son relativos al tamaño propio del elemento, así que translateY(100%) ajusta cajones y toasts de cualquier altura.

5. Curva y duración, emparejadas por uso

Nunca elijas el número más cercano a tu suposición. Indica el uso ("cierre de menú", "cambio de icono"), luego toma esa fila de references/tokens.md. Si ninguna fila coincide con el uso, añade un nuevo token con el nombre del uso; no adaptes uno existente. Por qué: un token es una declaración sobre para qué es la animación, así que un número cercano con el uso incorrecto es el token equivocado.

  • Entrada o salida: --ease-out. Moviéndose en pantalla: --ease-in-out. Cajones: --ease-drawer. Color: ease. Spinners: linear. Nunca ease-in.
  • Cualquier cosa arrastrable o interrumpible en pleno vuelo usa un spring, no una curva. Por qué: una curva no puede aceptar la velocidad que tenía la mano del usuario.
  • Sensación lenta: recorta la duración primero, luego la distancia, y solo entonces toca la curva.

6. Interrupción

  • Cualquier cosa que el usuario pueda activar dos veces en un segundo es una transición o un spring, nunca @keyframes. Por qué: una transición reorienta desde el valor actual; los keyframes se reinician y saltan.
  • WAAPI: cancela la animación anterior después de leer el valor actual, y comienza la nueva desde ese valor (references/recipes.md).
  • Una alternancia pulsada 10 veces debe terminar en el estado correcto sin saltos. Pruébalo.

7. Salida

  • La salida por defecto es un fade, más corto que la entrada (el archivo de tokens tiene cada par).
  • Cualquier cosa con una dirección (cajón, panel, toast deslizado) se va por donde vino.
  • El elemento que sale deja de ocupar espacio de inmediato, así que los hermanos cierran el hueco mientras se desvanece.
  • Las salidas son simultáneas y nunca escalonadas. Por qué: el usuario ya decidió irse.

8. Movimiento reducido, enviado con la animación

Opacidad y color se quedan. Los deslizamientos, escalas, desenfoques y rebotes se van; los deslizamientos se convierten en fades, el rebote se convierte en 0. Nunca uses el movimiento como la única señal. Patrón en references/recipes.md.

Coreografía

Asigna un rol a cada elemento en movimiento antes de temporizarlo:

RolTratamiento
Principal (la única cosa a notar)Se mueve primero, viaja más
SecundarioSigue, viaja menos
DecoraciónSe desvanece en su lugar, o nada
Estático (contenedores, chrome)Nunca se mueve
  • Una entrada por contenedor. Si el panel se desliza hacia adentro, su contenido ya está ahí. Por qué: dos entradas superpuestas hacen que el usuario espere el doble.
  • Ordena por importancia, no por orden del DOM. El retraso se mantiene en los pasos de values.md (40ms entre elementos, 100ms entre título, texto y acciones). Varía la distancia y la duración por rol en lugar del retraso.
  • Limita el escalonamiento de una lista al índice 6 (un retraso máximo de 240ms); los elementos posteriores comparten ese retraso. La entrada funciona mientras se reproduce.
  • Nunca escaleones un menú, paleta de comandos, contenido de pestaña o cualquier apertura repetida.
  • Quédate quieto: cualquier cosa que el usuario esté a punto de hacer clic, cualquier cosa ya en pantalla cuando la página se carga de nuevo, y una actualización que llegue dentro de 150ms de la anterior (salta al estado final).
  • La dirección sigue el significado: lo siguiente entra desde la derecha, lo anterior desde la izquierda; las cosas que el usuario activó crecen hacia afuera desde el activador.

Cargar cuando sea necesario

  • references/tokens.md: carga para cualquier valor exacto de duración, distancia, escala, desenfoque, easing o spring, y para tokenizar una base de código existente.
  • references/recipes.md: carga al construir un menú, popover, diálogo, cajón, toast, entrada de lista, cambio de icono, cambio de altura, indicador de pestaña o cambio de número.
  • references/gestures.md: carga para arrastrar, deslizar, deslizar rápido, paneles, o cualquier cosa que siga a un puntero.
  • references/performance.md: carga cuando la animación pierde fotogramas, antes de recurrir a will-change, y cuando las actualizaciones llegan rápido.

Pares

RotoArregladoPor qué
.menu { transition: all 300ms ease-in }transition: opacity 200ms, transform 200ms var(--ease-out)Propiedades nombradas; ease-in es lento; menús ≤ 200ms
scale(0) a scale(1)scale(0.95) y opacity: 0 a 1Nada aparece de la nada
Popover se escala desde su centrotransform-origin: var(--transform-origin)Debería crecer desde su activador
.open { animation: slide-in 300ms }transition: transform en el estado alternadoLos keyframes se rompen al ser interrumpidos
Cada fila animation-delay: i * 120msmin(i, 6) * 40msLa última fila llega en menos de 300ms
El cajón se desvanece después de deslizarse hacia adentroSe desliza hacia atrás por donde vinoLa dirección es la explicación
Liberación de arrastre en un ease-out fijoUn spring alimentado con la velocidad de liberaciónEl impulso de la mano continúa
setY(y) en pointermoveel.style.transform = ...Sin re-render por fotograma

Antes de terminar

Busca en el diff, luego verifica.

BuscaArregla
transition: all, will-change en *, ease-inPropiedades nombradas, elimina, --ease-out
scale(0), transform-origin: center en un popover0.95, el origen del activador (los diálogos se quedan centrados)
@keyframes en una clase que se alternaUna transición
Una duración superior a su fila en tokens.md, o un número no en tokens.mdEl token del uso
Animación en manejadores keydown o una paletaElimínala
width, height, top, left, box-shadow en una transicióntransform, opacity, o la receta
Sin ruta prefers-reduced-motionAñádela

Verifica en la aplicación en ejecución: reprodúcela a 4× (panel Animations de DevTools, o multiplica las duraciones), pulsa cualquier alternancia repetidamente, prueba con movimiento reducido activado, y acelera la CPU 4×. Indica cuál de estos no pudiste ejecutar.

Individual skills in this repo

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

nkurunziza-saddy/break

Stress-tests a piece of UI with worst-case data and every reachable state, then reports what broke with a numbered fix for each. Use it when the user types /break, or asks to "break this", "stress-test", "try the worst case", "what happens with long names", "check the empty and error states" or "find the edge cases" on a component or screen.

nkurunziza-saddy/layout

Structure and space in product UI on the web. It sets the spacing scale, grouping, alignment, density (compact or comfortable), hit areas, app shells (sidebar, toolbar, content, inspector), max widths, container-query responsiveness, dropdown and popover sizing, room for long and translated text, layout stability (no shift on load) and sticky elements that must not cover focus.

nkurunziza-saddy/pick-library

Picks the right library for a frontend task from a curated, status-checked list, instead of hand-rolling it or installing an abandoned package. Use it when the user asks "what should I use for…", "is there a library for…", or names a package, and when you are about to build a toast, command menu, drawer, date picker, table, virtual list, drag and drop, chart, OTP input, animated number, theme switch, form validation…

nkurunziza-saddy/surfaces

What product UI is made of on the web. It sets elevation levels with exact shadow recipes for light and dark mode, when to use a shadow and when a border, the transparent border for forced-colours mode, a small radius scale with concentric nesting, image outlines, every interactive state as a surface change (hover, pressed, selected, disabled, focus-visible), icons (one set, currentColor, outline and fill, stroke tha…

Skills relacionados