FORMA Design System / Motion Audit
| # | Dimensión | Score | Hallazgo principal |
|---|---|---|---|
| 1 | Token Architecture | 4 | ✓ --dur-fast/base/slow + --ease-expo/quart/exit — tokens completos, bien nombrados, usados consistentemente. Único gap: --easing-standard referenciado en cards.css pero no definido. |
| 2 | Accessibility | 4 | ✓ Global reset en shared.css (animation + transition + iteration-count). JS del cubo lee la media query antes del RAF. Hero SVG y scroll cue cubiertos individualmente. Cobertura exemplar. |
| 3 | Duration Calibration | 2 | Secuencia de entrance en páginas internas llega a 1600ms. Sidebar stagger: 1120ms. Nav overlay: 500ms. Todas las duraciones son correctas para first-load marketing; son altas para una tool usada diariamente. |
| 4 | Easing Integrity | 2 | --easing-standard no definido → arrow transitions usan browser ease. Logo frame draw usa cubic-bezier(0.4,0,0.2,1) (ease-in-out) — debería ser ease-out. Dos instancias, ambas visibles. |
| 5 | State Feedback | 3 | ✓ Hover transitions en botones, inputs y sidebar correctos. ✗ Sin scale(0.97) en :active de botones. Bento cell hover colors sin transition. Toasts con feedback correcto. |
| Total | 15/20 | Good — 5 issues Important abiertos · base técnica sólida · durations y easing a calibrar |
--easing-standard indefinido en cards.css — arrow transitions usan browser ease en lugar de --ease-expocubic-bezier(0.4,0,0.2,1) (ease-in-out) — debe ser ease-out para stroke naturaltransition: transform 500ms — demasiado lento para navegación diaria. Target: 240msscale(0.97) en :active — feedback táctil ausente en el elemento interactivo más frecuenteLens principal. Pregunta central: "¿Deberían estas animaciones existir en su forma actual?" FORMA se visita diariamente — la frecuencia cambia el estándar de duración.
Contexto de evaluación
FORMA es una tool de documentación visitada frecuentemente. Un engineer que navega entre Components, Guidelines y Tokens varias veces por sesión. La regla de frecuencia de Emil: interacciones diarias → animaciones sutiles bajo 300ms, sin delight en cada tap. FORMA aplica las duraciones correctas para una landing page (700ms, 1000ms de delay, stagger visible) en páginas que se usan como referencia.
--easing-standard indefinido — card article arrow usa browser easeLa regla .card-article__arrow usa var(--easing-standard) para la transición de transform y opacity. Este token no existe en tokens.css. Los tokens definidos son --ease-expo, --ease-quart, y --ease-exit.
Una propiedad custom CSS indefinida resuelve al valor initial de la propiedad — para transition-timing-function, ese valor es el browser built-in ease (curva simétrica que acelera en el medio). El arrow aparece con una curva que no coincide con ningún otro elemento interactivo del sistema.
Fix: cards.css:451 — cambiar var(--easing-standard) por var(--ease-expo). Dos instancias en la misma declaración.
ease-in-out — el stroke debería decelerar, no acelerarLa animación del rectángulo SVG usa cubic-bezier(0.4, 0, 0.2, 1), que es la curva estándar ease-in-out de Material Design. Para un stroke-dashoffset draw, esto significa: el trazo empieza lentamente, acelera en el medio, y desacelera al final. La fase de aceleración se siente mecánica — los trazos físicos no se aceleran en el medio, deceleran al llegar a su destino.
Los elementos del letterform F que siguen correctamente usan cubic-bezier(0.16, 1, 0.3, 1) (expo-out). El frame draw debería ser consistente y además es el primer elemento en animar — define la expectativa del resto.
Fix: Cambiar cubic-bezier(0.4, 0, 0.2, 1) a cubic-bezier(0.16, 1, 0.3, 1) en #hero-mark rect:nth-of-type(1). Una línea.
El panel del nav overlay usa transition: transform var(--dur-base) var(--ease-expo) donde --dur-base: 500ms. El scrim usa la misma duración para opacity. 500ms es medio segundo — perceptiblemente lento cuando el usuario lo trigger en cada sesión para navegar entre secciones en mobile.
--dur-base es la duración correcta para elementos de first-load como el hero stat-row o los sidebar groups. Para un panel de navegación que se abre y cierra múltiples veces por sesión, la duración target es 200–240ms.
Fix: En shared.css:196 (panel) y shared.css:186 (scrim), cambiar var(--dur-base) por var(--dur-fast) (240ms). La easing expo-out sigue siendo apropiada — solo más rápida.
Las páginas internas (components.html, guidelines.html) usan hero.css con stagger hasta 1000ms de delay + animación de 600ms = 1600ms total. Los sidebar groups staggerean hasta 400ms de delay + 720ms = 1120ms. En index.html esta duración es justificada — primera impresión, momento cinematográfico. En páginas de referencia que el usuario carga múltiples veces por sesión, es latencia percibida en cada navegación.
El cubo de index.html tiene su propio sistema de entrance (logos, wordmark, tagline) que no se reutiliza en páginas internas — bien. El problema es que hero.css aplica la misma lógica de "primeras impresiones" a pages de tool.
Fix: En hero.css, comprimir stagger delays a máximo 150ms total (0 / 50 / 100 / 150ms en lugar de 0 / 560 / 680 / 840ms). En sidebar.css, remover stagger o comprimir a 80ms max total. Durations al 300ms máximo. Considerar una clase .hero--tool con timings reducidos para páginas internas.
:active scale — feedback táctil ausenteEl selector .btn transiciona background-color, border-color, color, y box-shadow. No incluye transform. Sin un scale(0.97) en :active, los botones no dan feedback inmediato de que el click registró — la única confirmación es visual (color) y llega después del procesamiento de la acción.
Los botones de FORMA se usan en cada demo de components (copy token, acciones), en el header, y en los CTAs de artículos. Es el elemento interactivo con más frecuencia de uso en todo el sistema.
Fix: Agregar transform a la lista de transición de .btn, luego .btn:active { transform: scale(0.97); }. Una regla, todos los botones heredan el feedback.
Lo que funciona bien:
cancelAnimationFrame cuando el hero sale del viewport. No hay GPU waste en tabs background ni durante el scroll normal. Técnicamente correcto y frecuentemente omitido. — index.html:1726
var(--dur-fast) — exactamente calibrado para un elemento que se trigger con alta frecuencia. No interrumpe el flujo. — shared.css:343
.in y luego deja de observar el elemento. Los elementos no se re-animan al hacer scroll hacia atrás. Patrón correcto. — components.html:962
.btn transiciona background-color, color, box-shadow — ninguna propiedad de layout. Sin layout thrash, sin reflow. — components.css:345
Lens secundario. Pregunta: "¿Está esto lo suficientemente pulido para producción?" Después de que Emil determine que algo debería animar, Jakub define cómo.
Contexto de evaluación
FORMA tiene la arquitectura de motion correcta — tokens, fills, reducción de willChange. La oportunidad de Jakub es en los detalles de exit vocabulary y en que --ease-exit está definido pero nunca se usa. Las exits son tan prominentes como los enters — el overlay se cierra con la misma curva que abre.
animation-fill-mode: both en todos los elementos, y easing expo-out en el letterform. El resultado es una construcción visible del logo — no decoración. — index.html:820
transform-box: fill-box; transform-origin: 0% 50% ancla el scaleX al borde izquierdo. Las barras se extienden hacia la derecha, no desde el centro. Origin-aware — exactamente la sensibilidad de Jakub. — components.css:706
--ease-exit definido en tokens: cubic-bezier(0.4, 0, 1, 1) — ease-in, aceleración hacia la salida. El vocabulario existe. Que esté definido y sin uso es la oportunidad más clara del sistema. — tokens.css:497
--ease-exit sin usar: El nav overlay cierra con --ease-expo (mismo que abre). Los exits deberían acelerar hacia la salida (--ease-exit), no decelerar. Una línea en shared.css donde el panel hace translateX(-100%) al cerrar.
opacity + translateY y sale revirtiendo las mismas propiedades. Jakub: las salidas deben ser más sutiles. Un fade simple en 150ms al cerrar (solo opacity) se sentiría más refinado que la entrada-en-reversa actual.
Lens selectivo — aplica solo al hero de index.html y a momentos de primer contacto. El sistema correctamente se restraints en páginas de tool.
Contexto de evaluación
El cubo 3D con mouse tracking y la animación del logo son los únicos lugares en FORMA donde la latitud creativa es apropiada — y están bien ejecutados. La oportunidad de Jhey es el bento grid: el landing page que explica un sistema de diseño podría demostrar scroll-driven animation usando scroll-driven animation.
offsetX += (targetOffsetX - offsetX) * 0.08 por frame. El número es correcto: suficientemente suave para evitar jitter, suficientemente rápido para sentirse responsive. No usa CSS variables para el update (correcto — actualiza element.style.transform directamente). — index.html:1724
@keyframes + animation-timeline: scroll() podría hacer que cada celda entre en su posición a medida que el usuario scrollea — sin JavaScript, con @media (prefers-reduced-motion: reduce) como guard natural. La landing page sobre un sistema de diseño demostrando su propia filosofía de motion.
opacity + scale(0.8→1) + blur(2px→0) daría feedback inmediato dentro del botón, antes de que el toast llegue.
@property para tokens de color animables: Definir @property --color-blue-400 como tipo <color> habilitaría transiciones suaves entre valores de tokens en cambios de tema. Preparación para un dark mode toggle animado.
5 issues P1. Ordenados por impacto visible / esfuerzo de fix:
[P1 · 2min] En cards.css:451, reemplazar var(--easing-standard) por var(--ease-expo). Fix inmediato al único token indefinido del sistema.
[P1 · 2min] En index.html:876, cambiar el easing del frame draw de cubic-bezier(0.4,0,0.2,1) a cubic-bezier(0.16,1,0.3,1). Consistente con los elementos F subsecuentes.
[P1 · 5min] Agregar transform a la transición de .btn + regla .btn:active { transform: scale(0.97); } en components.css:345. Feedback táctil en todos los botones.
[P1 · 10min] En shared.css:186,196, cambiar nav overlay de var(--dur-base) (500ms) a var(--dur-fast) (240ms). Navegación diaria al ritmo correcto.
[P1 · 20min] Comprimir entrance sequences de páginas internas: hero.css delays al 150ms total, sidebar.css stagger al 80ms total, durations al 300ms máximo. Crear clase .hero--tool si se quiere mantener el timing cinematográfico solo en index.html.
Reporte generado con /design-motion-principles · Emil primary · Jakub secondary · Jhey selectivo.
Ver el reporte técnico completo con demos en motion-audits/forma-2026-06-05.html.