Communitygithub.com

RevanthThota55/FreeFrame-Studio

El enfoque de Apple para el diseño de interfaces y el movimiento físico y fluido, traducido para la web. Úselo al construir o revisar interfaces basadas en gestos, animaciones con resortes, interacciones de arrastre/deslizamiento/hojas, momentum y transiciones interrumpibles, materiales translúcidos y profundidad, tipografía (tamaño óptico, tracking, interlineado), movimiento reducido, o los fundamentos de diseño (retroalimentación, consistencia espacial, moderación) detrás de las interfaces al estilo Apple.

¿Qué es FreeFrame-Studio?

Este skill traduce los principios de diseño de interfaces fluidas de Apple, extraídos de charlas de WWDC como 'Designing Fluid Interfaces' (2018), al contexto del desarrollo web moderno. Proporciona pautas detalladas sobre cómo implementar interacciones que se sientan naturales y receptivas, utilizando tecnologías web como CSS, Pointer Events, requestAnimationFrame y bibliotecas de resortes como Motion o Framer Motion. El skill se centra en conceptos clave como la respuesta inmediata al tacto, la manipulación directa con seguimiento 1:1, la interrumpibilidad de las animaciones, el uso de resortes en lugar de animaciones de duración fija, y la transferencia de velocidad entre gestos y animaciones. También cubre técnicas avanzadas como la proyección de momentum, el 'rubber-banding' (resistencia progresiva en los límites), y la creación de profundidad y jerarquía visual a través de materiales translúcidos y desenfoques. Además, se abordan principios de consistencia espacial, diseño de gestos (toque, arrastre, deslizamiento), y la integración de retroalimentación multimodal (moción, sonido y háptica). Es ideal para desarrolladores que buscan crear interfaces web con una sensación de fluidez y pulido similares a las de las plataformas de Apple, ofreciendo tanto la teoría como ejemplos prácticos de código. El skill está diseñado para ser una guía completa, desde los fundamentos filosóficos hasta los detalles de implementación técnica, ayudando a los desarrolladores a traducir la filosofía de diseño de Apple a la plataforma web de manera efectiva.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/RevanthThota55/FreeFrame-Studio/tree/HEAD/.claude/skills/apple-design

Preguntar en tu IA favorita

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

Documentación

Diseño Apple

Respuesta Inicial

Cuando este skill se invoque por primera vez sin una pregunta específica, responda únicamente con:

Estoy listo para ayudarte a construir interfaces fluidas al estilo Apple en la web; mi conocimiento proviene de las charlas de diseño de WWDC de Apple, traducido para la web.

No proporcione ninguna otra información hasta que el usuario haga una pregunta.

Cómo Apple construye interfaces que dejan de sentirse como una computadora y comienzan a sentirse como una extensión de ti. Este conocimiento proviene de las charlas de diseño de WWDC de Apple — principalmente Diseñando Interfaces Fluidas (WWDC 2018) — destilado y traducido para la plataforma web (CSS, Pointer Events, requestAnimationFrame, bibliotecas de resortes como Motion/Framer Motion).

El hilo conductor: una interfaz se siente viva cuando el movimiento comienza desde el valor actual en pantalla, hereda la velocidad del usuario, proyecta el momentum hacia adelante y puede ser agarrada e invertida en cualquier instante. Los resortes son la herramienta que hace que todo esto sea natural, porque son inherentemente interrumpibles y conscientes de la velocidad.

La Idea Central

"Cuando alineamos la interfaz con la forma en que pensamos y nos movemos, ocurre algo mágico: deja de sentirse como una computadora y comienza a sentirse como una extensión perfecta de nosotros."

Una interfaz es fluida cuando se comporta como el mundo físico: las cosas responden instantáneamente, se mueven de forma continua, llevan momentum, resisten en los límites y pueden ser redirigidas a mitad del movimiento. Todo lo que sigue es una forma de acercarse a eso.

Apple enmarca el diseño como un servicio a cuatro necesidades humanas: seguridad/previsibilidad, comprensión, logro y alegría. Cada regla aquí sirve a una de ellas.

1. Respuesta — eliminar la latencia

En el momento en que aparece el retraso, la sensación de inmediatez "se desploma". La respuesta es la base sobre la que se construye todo lo demás.

  • Responder al presionar, no al soltar. Resalte un botón en el instante en que se presiona. Esperar a click/levantar el dedo para mostrar retroalimentación se siente muerto.
  • Esté atento a cada latencia. Audite los 'debounces', temporizadores artificiales, esperas de transición y el retraso de ~300ms del toque. Cualquier cosa en la ruta de entrada que no sea esencial es una regresión.
  • La retroalimentación debe ser continua durante la interacción, no solo al final. Para un arrastre, control deslizante o cajón, actualice la UI 1:1 con el puntero durante todo el proceso — nunca anime solo cuando el gesto se completa.
/* La retroalimentación vive en la pulsación, y es instantánea */
.button:active {
  transform: scale(0.97);
  transition: transform 100ms ease-out;
}

2. Manipulación directa — seguimiento 1:1

"El toque y el contenido deben moverse juntos."

Cuando el usuario arrastra algo, debe permanecer pegado al dedo — y respetar el desplazamiento desde donde lo agarró. Ajustar al centro del elemento al agarrarlo rompe la ilusión de inmediato.

  • Use Pointer Events con setPointerCapture para que el seguimiento continúe incluso cuando el puntero sale de los límites del elemento.
  • Realice un seguimiento de un breve historial de velocidad/posición (los últimos eventos pointermove), no solo el punto actual — necesitará la velocidad al soltar.
el.addEventListener('pointerdown', (e) => {
  el.setPointerCapture(e.pointerId);
  const grabOffset = e.clientY - el.getBoundingClientRect().top; // respeta dónde agarró
  // ...rastrear historial de posición + marca de tiempo para la velocidad
});

3. Interrumpibilidad — el principio más importante

"El pensamiento y el gesto ocurren en paralelo."

Cada animación debe ser interrumpible y redirigible en cualquier momento. Un usuario debe poder agarrar un elemento en movimiento a mitad de vuelo e invertirlo sin esperar a que la animación termine. Un modal que se cierra y que el usuario vuelve a agarrar debe seguir al dedo — no terminar de cerrarse primero y luego reabrirse.

  • Nunca bloquee la entrada durante una transición.
  • Anime siempre desde el valor de presentación (actual), nunca desde el valor objetivo. Al interrumpir, lea la transformación en vivo del elemento en pantalla e inicie la nueva animación desde allí. Comenzar desde el valor lógico/objetivo provoca un salto visible.
  • Evite las transiciones CSS y @keyframes para cualquier cosa impulsada por gestos — no se pueden agarrar e invertir suavemente a mitad de vuelo. Los resortes animan desde el valor actual por defecto, que es exactamente lo que necesita la interrupción.
  • Cuando un gesto se invierte, mezcle la velocidad — no la corte abruptamente. Reemplazar una animación con otra en una inversión crea una discontinuidad de velocidad, un "muro de ladrillos". Las bibliotecas de resortes que transportan la velocidad a través de un redestino lo evitan. (Esto es lo que las animaciones aditivas de iOS hacen de forma nativa; en la web, elija una biblioteca de resortes que redestine desde la velocidad actual.)
  • Descomponga el movimiento 2D en resortes X e Y independientes. Un solo resorte en una distancia 2D se desincroniza cuando X e Y tienen diferentes velocidades.

4. Comportamiento sobre animación — use resortes

"Piense en la animación como una conversación entre usted y el objeto, no como algo prescrito por la interfaz."

Una animación preprogramada de duración fija no puede responder a nuevas entradas. Un resorte sí puede — una nueva entrada simplemente cambia el objetivo, y el movimiento permanece continuo. Recurra a los resortes para cualquier cosa que un usuario pueda tocar.

Apple reemplazó deliberadamente el trío de física (masa/rigidez/amortiguación) con dos parámetros adaptados para diseñadores. Piense en estos:

  • Relación de amortiguación — controla el sobreimpulso. 1.0 = amortiguación crítica, sin rebote, asentamiento suave. < 1.0 = sobrepasa y oscila. Cuanto más bajo, más rebote.
  • Respuesta — qué tan rápido el valor alcanza el objetivo, en segundos. Más bajo = más rápido. Esto no es "duración" — un resorte no tiene una duración fija; su tiempo de asentamiento surge de los parámetros.

Valores por defecto:

  • Inicie la mayoría de las UI con amortiguación 1.0 (amortiguación crítica) — elegante y no distractora.
  • Agregue rebote (amortiguación ~0.8) solo cuando el gesto en sí mismo haya llevado momentum (un lanzamiento, un tirón, una liberación de arrastre). El sobreimpulso en un menú que simplemente apareció se siente mal; el sobreimpulso en una tarjeta que lanzó se siente bien.

Valores concretos que Apple envía:

InteracciónAmortiguaciónRespuesta
Mover / reposicionar (ej. PiP)1.00.4
Rotación0.80.4
Cajón / hoja0.80.3

Mapeo web (Motion / Framer Motion): la API de resorte bounce + duration se asigna estrechamente a la amortiguación + respuesta de Apple. Un estilo base seguro es usar resortes con damping: 1.0 por defecto; reserve el rebote para interacciones físicas impulsadas por momentum.

import { animate } from 'motion';

// Predeterminado con amortiguación crítica (sin sobreimpulso)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });

// Interacción con momentum — un poco de rebote, solo porque lo precedió un lanzamiento
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });

5. Transferencia de velocidad — la sutura entre arrastre y animación

Cuando un gesto termina, la animación debe continuar a la velocidad exacta del dedo, para que no haya una sutura visible entre arrastrar y animar. Este es el detalle que más separa lo "fluido" de lo "correcto".

Pase la velocidad de liberación del puntero como la velocidad inicial del resorte. Algunas APIs de resortes quieren la velocidad relativa — normalícela por la distancia restante al objetivo:

velocidadRelativa = velocidadGesto / (valorObjetivo − valorActual)

Ejemplo: elemento en y=50, objetivo y=150 (100px por recorrer), dedo moviéndose a 50px/s → velocidad inicial del resorte = 50 / 100 = 0.5. Framer Motion / Motion toman la velocidad absoluta en px/s directamente (opción velocity), por lo que generalmente se le pasa el valor crudo.

6. Proyección de momentum — animar hacia donde se dirige el gesto

"Tome una entrada pequeña y produzca una salida grande."

No ajuste al límite más cercano desde el punto de liberación. Use la velocidad para proyectar la posición de reposo — exactamente como la desaceleración del desplazamiento — luego ajuste al objetivo más cercano a ese punto proyectado. Esto es lo que hace que un lanzamiento se sienta como si arrojara el elemento.

La función de proyección exacta de Apple (del código de muestra de Diseñando Interfaces Fluidas):

// decelerationRate ≈ 0.998 para una sensación de desplazamiento normal; 0.99 para más rápido
function project(initialVelocity /* px/s */, decelerationRate = 0.998) {
  return (initialVelocity / 1000) * decelerationRate / (1 - decelerationRate);
}

const projectedEndpoint = currentPosition + project(releaseVelocity);
const target = nearestSnapPoint(projectedEndpoint);   // elegir objetivo de la proyección
animateSpringTo(target, { velocity: releaseVelocity }); // luego transferir velocidad (§5)

Nota: la fórmula física v²/(2·decel) no es lo que Apple envía — use la forma de decaimiento exponencial anterior. Este es el comportamiento estándar en buenos paneles inferiores y carruseles (Vaul, Embla).

7. Consistencia espacial — rutas simétricas, orígenes anclados

"Si algo desaparece de una manera, esperamos que emerja de donde vino."

  • Entre y salga por el mismo camino. Un panel que se desliza desde la derecha debe desaparecer hacia la derecha. Entrar por la derecha / salir por abajo se siente desconectado y confuso.
  • Ancle las interacciones a su origen. Un menú, ventana emergente u hoja debe originarse desde el elemento que lo desencadenó — establezca transform-origin en el desencadenante, para que la relación espacial entre el botón y el contenido sea obvia. (Este es el mismo punto de conciencia del origen que las ventanas emergentes que escalan desde su desencadenante, no desde su centro).
  • Refleje la aceleración en las transiciones reversibles para que la ruta de salida coincida con la ruta de retorno (use puntos de control cúbico-bezier inversos para las dos direcciones).

8. Insinúe en la dirección del gesto

Los humanos predicen un estado final a partir de una trayectoria. El movimiento intermedio debe telegrafiar hacia dónde se dirigen las cosas — los módulos del Centro de Control "crecen hacia arriba y hacia afuera hacia su dedo". Haga que los fotogramas intermedios apunten al resultado, no solo interpolar ciegamente hacia él.

9. Efecto elástico ('Rubber-banding') — límites suaves

En un borde, resista progresivamente en lugar de detenerse bruscamente. Una parada brusca se lee como "congelado"; la resistencia continua se lee como "receptivo, pero no hay nada más aquí". Aplique una amortiguación que aumente cuanto más allá del límite arrastre el usuario.

// Cuanto más allá del límite, menos sigue el elemento — las cosas reales se ralentizan antes de detenerse
function rubberband(overshoot, dimension, constant = 0.55) {
  return (overshoot * dimension * constant) / (dimension + constant * Math.abs(overshoot));
}

10. Detalles de diseño de gestos (la lista de verificación de "sensación")

  • Toque: resalte al presionar (instantáneo), confirme al levantar. Agregue ~10px de histéresis/relleno de acierto alrededor del objetivo y permita la cancelación arrastrando hacia afuera y luego regresando.
  • Arrastre/deslizamiento: requiera un pequeño umbral de movimiento (histéresis, ~10px) antes de comprometerse con una dirección, luego rastree 1:1.
  • Detecte todos los gestos plausibles en paralelo desde el primer movimiento, luego cancele con confianza los perdedores una vez que la intención esté clara. Evite los reconocedores que solo informan un estado final (eventos tipo swipeleft) — estos descartan el seguimiento continuo que necesita para la retroalimentación.
  • Minimice los retrasos de desambiguación. La detección de doble toque inevitablemente retrasa los toques simples; solo pague ese costo donde exista realmente el doble toque.

11. Suavidad a nivel de fotograma

La suavidad se trata de lo que hay en los fotogramas, no solo de la tasa de fotogramas.

  • Mantenga el cambio de posición por fotograma por debajo del umbral de percepción para evitar el estroboscópico.
  • Para movimientos muy rápidos, un sutil desenfoque de movimiento / estiramiento codifica la velocidad y se lee mejor que una raya nítida y dura.
  • requestAnimationFrame es el reloj sincronizado con la pantalla de la web (Apple usa CADisplayLink). Anime solo propiedades amigables con el compositor — transform y opacity — y sugiera con will-change donde el movimiento sea inminente.

12. Materiales y profundidad — la translucidez transmite jerarquía

Apple usa materiales translúcidos como una capa funcional flotante que aporta estructura sin robar el enfoque. En la web, aproxímese con backdrop-filter.

  • Construya navegación/barras de herramientas/hojas como capas translúcidas (backdrop-filter: blur() + un fondo semitransparente) con contenido desplazándose debajo — no barras opacas que consuman una franja fija.
  • El peso del material codifica la jerarquía: los materiales más oscuros/más pesados separan regiones estructurales (barras laterales); los materiales más claros atraen la atención hacia elementos interactivos (botones). Nunca apile una superficie translúcida clara sobre otra — la legibilidad colapsa.
  • Las superficies más grandes deben leerse como más gruesas: un desenfoque más fuerte + una sombra más profunda que en pequeñas fichas. Considere una sombra consciente del contexto — más pesada sobre contenido ocupado/texto para separación, más clara sobre fondos lisos.
  • Atenuar para enfocar, separar para mantener el flujo. Una tarea modal empareja la superficie con un velo de atenuación y empuja el fondo hacia atrás/abajo. Un panel paralelo y no bloqueante usa translucidez y desplazamiento sin un velo para que el flujo no se rompa. Para hojas apiladas, atenúe y empuje progresivamente hacia atrás cada capa principal.
  • La vitalidad ('Vibrancy') mantiene el texto legible sobre fondos cambiantes. Sobre superficies desenfocadas/translúcidas, no use texto gris plano — use un contraste más alto, un peso ligeramente más pesado y un pequeño aumento en el espaciado entre letras. Coloque el color sobre una capa sólida, no sobre el primer plano translúcido.
  • Efectos de borde de desplazamiento, no divisores duros. En lugar de un borde de 1px debajo de un encabezado fijo, desvanezca una pequeña máscara de desenfoque/gradiente donde el contenido se encuentra con el cromo flotante — solo donde la UI flotante se superpone realmente al contenido.
  • Materialice, no solo se desvanezca. Para superficies de vidrio/desenfoque, anime el radio de desenfoque y la escala juntos al entrar/salir, para que la superficie se lea como un material real que llega en lugar de un desvanecimiento de opacidad simple.
.toolbar {
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(20px) saturate(180%);
  border-top: 1px solid rgba(255, 255, 255, 0.4); /* borde superior brillante = luz que incide en el material */
}

13. Retroalimentación multimodal — movimiento + sonido + háptica

Tres reglas para combinar los sentidos (de Diseñando Experiencias Audio-Hápticas):

  1. Causalidad — debe ser obvio qué causó la retroalimentación. Actívela en el evento causal real (el interruptor que cambia, el elemento que encaja en su lugar), y haga coincidir su carácter con la fisicalidad de la acción.
  2. Armonía — lo visual, el sonido y la háptica deben dispararse en el mismo fotograma. La latencia entre ellos destruye la ilusión. No permita que un...

Individual skills in this repo

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

RevanthThota55/FreeFrame-Studio

Build an animation from scratch, making the decisions in the order that determines whether it feels right — should it animate at all, what purpose, which tool, which properties, which curve and duration, how it interrupts, how it exits. Writes the implementation. Use when asked to animate something, add motion, make a component feel alive, or build a transition. For critiquing existing motion use review-animations; for auditing a whole codebase use improve-animations.

RevanthThota55/FreeFrame-Studio

Keep web animations inside the frame budget — animate composite-only properties, keep motion off the main thread when the page is busy, and find the cause when an animation drops frames. Covers the layout/paint/composite pipeline, cheaper property swaps, CSS vs WAAPI vs requestAnimationFrame, Framer Motion's hardware-accelerated path, React re-rendering per frame, inherited CSS variable recalculation, blur cost, and when `will-change` actually helps. Use when an animation is janky, choppy, stutters, or drops frames; when choosing which property to animate; when deciding between CSS and JS animation on performance grounds; or when reaching for `will-change` or GPU layers. For choosing easing, duration, or whether to animate at all use animate; for reviewing motion as a whole use review-animations.

RevanthThota55/FreeFrame-Studio

Reverse-lookup glossary that turns a vague description of a web animation or motion effect into its exact term ("the bouncy thing when a popover opens" → Pop in; "the iOS rubber-band scroll" → Rubber-banding). Use when the user asks "what's it called when…", or describes a motion effect without knowing its name and wants the right word to prompt an AI or designer with. For naming an effect, not designing or building one.

Skills relacionados