Motion

La escala que no miente

5 min

Animar desde scale(0) no es una decisión de diseño. Es teleportación.

Un modal aparece desde el centro de la pantalla. Escala de cero a uno. Se ve como PowerPoint.

Cambias el valor inicial a 0.97. El modal ahora emerge. La diferencia son tres puntos porcentuales. La percepción es completamente distinta.

No es magia. Es física.

Por qué scale(0) viola una expectativa

Nada en el mundo real aparece de la nada. Los objetos entran al campo visual — desde un borde, desde detrás de otro elemento, emergiendo desde una superficie. Tienen origen. Tienen trayectoria.

Un elemento que escala desde cero no entra. Aparece. El cerebro procesa eso como un glitch, no como movimiento con información.

El problema no es la animación. Es el valor inicial.

La diferencia no está en la duración ni en el easing — esos están documentados en Cuándo no animar. Está en el punto de partida.

El origen espacial importa tanto como el valor inicial

Hay un segundo error que ocurre junto al primero: el elemento animado escala desde su propio centro geométrico, no desde su trigger.

Un dropdown que escala desde el centro del viewport no tiene relación espacial con el botón que lo abrió. La animación ocurre en el lugar equivocado.

La regla es simple: el elemento debe emerger desde donde fue invocado.

Un dropdown abierto desde un botón en la esquina superior derecha debería escalar desde esa esquina. Un tooltip debería aparecer desde el elemento al que pertenece. Un popover desde su trigger exacto.

Esto no es solo estética. Es causalidad visual. El usuario necesita ver que el elemento que aparece tiene relación con la acción que ejecutó. Cuando el origen es incorrecto, la interfaz parece que hace cosas por su cuenta.

En CSS el origen se controla con transform-origin. En la mayoría de los componentes de librería este valor nunca se toca — va a center center por defecto. Ese default es incorrecto para casi todos los casos de uso reales.

/* Dropdown abierto desde un trigger arriba a la derecha */
.dropdown {
  transform-origin: top right;
  animation: enter 160ms ease-out;
}

@keyframes enter {
  from { transform: scale(0.95); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}
Misma animación — origen distinto. El popover emerge del trigger, no de sí mismo.

El valor inicial no es universal

El mismo valor inicial no funciona para todos los elementos. La amplitud correcta depende del tamaño del elemento y de su propósito.

Un modal grande que escala desde 0.85 se siente como si alguien lo lanzara hacia ti. Un tooltip que escala desde 0.99 prácticamente no animó — la animación no comunicó nada.

La tabla que falta en la mayoría de los design systems:

Elemento Scale inicial Por qué
Modal, drawer 0.97 Grande — poca amplitud, mucho peso
Dropdown, popover 0.95 Medio — amplitud moderada desde el trigger
Tooltip 0.85 Pequeño — más amplitud, movimiento relativo menor
Toast, notificación Sin scale Entra desde el borde, solo translate + opacity
Badge, chip 0.8 Pequeño y puntual — la amplitud confirma la aparición
Valores iniciales por tipo de componente — la tabla que debería vivir en el design system.

Los toasts y notificaciones de sistema son el caso especial. No escalan — entran desde fuera del viewport con translate. Una notificación que escala desde el centro compite visualmente con el contenido principal y no tiene origen espacial coherente.

El gap entre Figma y producción

Este es el problema real para un equipo.

En Figma diseñas el estado final. Smart Animate interpola entre frames. Se ve bien en el prototipo porque Figma nunca hace scale desde cero — el valor inicial está implícito en cómo construiste el componente.

El developer recibe la spec. Ve «animación de entrada, modal, ease-out». Implementa:

@keyframes enter {
  from { transform: scale(0); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
Técnicamente correcto según la spec. Visualmente incorrecto porque la spec no capturó el valor inicial ni el transform-origin.

No es un error de código. Es un error de documentación de sistema.

Un design system que no especifica el valor inicial de cada tipo de animación de entrada no está completo. El componente Modal en Figma debería tener anotado en su spec:

Entrada:
  scale inicial: 0.97
  opacity inicial: 0
  transform-origin: center (ajustar según posición del trigger)

Referencia: token --animation-modal-enter
No como sugerencia. Como constraint.

Si el developer tiene que adivinar el valor inicial, el sistema falló antes de que escribiera una línea de código.

La regla

El valor inicial nunca es cero.

El transform-origin siempre apunta al trigger.

Y en el design system: cada componente flotante tiene su valor inicial y su origen documentados. No en un Notion que nadie lee — en la propia especificación del componente en Figma.