Communitygithub.com

ZainR525/PersonalWebsiteZainRizvi

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

¿Qué es PersonalWebsiteZainRizvi?

Este skill encapsula los principios de diseño de interfaces fluidas de Apple, extraídos de sus charlas de WWDC (principalmente 'Designing Fluid Interfaces' de 2018) y traducidos al contexto del desarrollo web con CSS, JavaScript y bibliotecas de resortes como Motion o Framer Motion. El núcleo es que una interfaz se siente viva cuando el movimiento comienza desde el valor actual en pantalla, hereda la velocidad del usuario, proyecta el momento hacia adelante y puede ser agarrada e invertida en cualquier instante. Proporciona pautas detalladas sobre respuesta inmediata, manipulación directa 1:1, interrumpibilidad de animaciones, uso de resortes físicos con parámetros de amortiguación y respuesta, transferencia de velocidad al finalizar un gesto, proyección de momento para determinar puntos de destino, coherencia espacial, límites suaves (rubber-banding), y diseño de gestos. También cubre aspectos visuales como materiales translúcidos con backdrop-filter y retroalimentación multimodal. Es compatible con cualquier proyecto web que busque una sensación nativa y pulida, y su documentación incluye ejemplos prácticos de código JavaScript y CSS.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ZainR525/PersonalWebsiteZainRizvi/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 invoca por primera vez sin una pregunta específica, responde solo 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 Apple en la WWDC, traducidas para la web.

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

Cómo construye Apple 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 Apple en la WWDC — principalmente Designing Fluid Interfaces (WWDC 2018) — destilado y traducido a 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 momento 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, sucede 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 momento, resisten en los límites y pueden redirigirse en medio del movimiento. Todo lo que sigue es una forma de acercarse a eso.

Apple enmarca el diseño como el 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 por un precipicio". La respuesta es la base sobre la que se construye todo lo demás.

  • Responde al presionar, no al soltar. Resalta un botón en el instante en que se presiona. Esperar a click/levantar el toque para mostrar retroalimentación se siente muerto.
  • Sé vigilante con cada latencia. Audita 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, deslizador o cajón, actualiza la interfaz de usuario 1:1 con el puntero durante todo el recorrido — nunca animar 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 agarrar rompe la ilusión de inmediato.

  • Usa Pointer Events con setPointerCapture para que el seguimiento continúe incluso cuando el puntero sale de los límites del elemento.
  • Rastrea un breve historial de velocidad/posición (los últimos eventos pointermove), no solo el punto actual — necesitarás la velocidad al soltar.
el.addEventListener('pointerdown', (e) => {
  el.setPointerCapture(e.pointerId);
  const grabOffset = e.clientY - el.getBoundingClientRect().top; // respeta dónde agarraron
  // ...rastrea la posición + la 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 medio vuelo e invertirlo sin esperar a que la animación termine. Un modal que se cierra y el usuario vuelve a agarrar debe seguir al dedo — no terminar de cerrarse primero y luego reabrirse.

  • Nunca bloquees la entrada durante una transición.
  • Siempre anima desde el valor presente (actual), nunca el valor objetivo. Al interrumpir, lee la transformación en vivo del elemento en pantalla e inicia la nueva animación desde ahí. Comenzar desde el valor lógico/objetivo causa un salto visible.
  • Evita las transiciones CSS y @keyframes para cualquier cosa impulsada por gestos — no se pueden agarrar e invertir suavemente a medio vuelo. Los resortes animan desde el valor actual por defecto, que es exactamente lo que necesita la interrupción.
  • Cuando un gesto se invierte, combina la velocidad — no la cortes bruscamente. Reemplazar una animación con otra en una inversión crea una discontinuidad de velocidad, un "muro de ladrillos". Las bibliotecas de resortes que arrastran la velocidad a través de un re-destino lo evitan. (Esto es lo que las animaciones aditivas de iOS hacen de forma nativa; en la web, elige una biblioteca de resortes que re-destine desde la velocidad actual).
  • Descompón el movimiento 2D en resortes X e Y independientes. Un solo resorte en una distancia 2D se desincroniza cuando X e Y tienen velocidades diferentes.

4. Comportamiento sobre animación — usa resortes

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

Una animación predefinida y de duración fija no puede responder a nuevas entradas. Un resorte sí — una nueva entrada solo cambia el objetivo, y el movimiento se mantiene continuo. Recurre a los resortes para cualquier cosa que el usuario pueda tocar.

Apple reemplazó deliberadamente el trío físico (masa/rigidez/amortiguación) con dos parámetros amigables para el diseñador. Piensa 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. Menor = más rebote.
  • Respuesta — qué tan rápido el valor alcanza el objetivo, en segundos. Menor = más ágil. Esto no es "duración" — un resorte no tiene duración fija; su tiempo de asentamiento surge de los parámetros.

Valores predeterminados:

  • Comienza la mayoría de las interfaces de usuario en amortiguación 1.0 (amortiguación crítica) — elegante y no distractor.
  • Agrega rebote (amortiguación ~0.8) solo cuando el gesto en sí mismo llevaba momento (un movimiento rápido, un lanzamiento, una liberación de arrastre). El sobreimpulso en un menú que acaba de aparecer se siente mal; el sobreimpulso en una tarjeta que has lanzado 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 de casa seguro es usar resortes con damping: 1.0 en todas partes por defecto; reserva el rebote para interacciones físicas impulsadas por el momento.

import { animate } from 'motion';

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

// Interacción de momento — un poco de rebote, solo porque lo precedió un movimiento rápido
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });

5. Transferencia de velocidad — la unión 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 unión visible entre arrastrar y animar. Este es el detalle que más separa lo "fluido" de lo "suficiente".

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

velocidadRelativa = velocidadDelGesto / (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 velocidad absoluta en px/s directamente (opción velocity), por lo que normalmente le pasas el valor sin procesar.

6. Proyección de momento — animar hacia donde va el gesto

"Toma una pequeña entrada y produce una gran salida."

No te ajustes al límite más cercano desde el punto de liberación. Usa la velocidad para proyectar la posición de reposo — exactamente como la desaceleración de desplazamiento — luego ajusta al objetivo más cercano a ese punto proyectado. Esto es lo que hace que un movimiento rápido se sienta como si lanzara el elemento.

La función de proyección exacta de Apple (del código de muestra de Designing Fluid Interfaces):

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

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

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

7. Coherencia espacial — caminos simétricos, orígenes anclados

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

  • Entra y sale por el mismo camino. Un panel que se desliza desde la derecha debe cerrarse hacia la derecha. Entrar desde la derecha / salir por la parte inferior se siente desconectado y confuso.
  • Ancla las interacciones a su origen. Un menú, popover u hoja debe originarse desde el elemento que lo activó — establece transform-origin en el activador, 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 los popovers que escalan desde su activador, no desde su centro).
  • Refleja la suavización en las transiciones reversibles para que el camino de salida coincida con el camino de retorno (usa puntos de control cúbico-bézier inversos para las dos direcciones).

8. Insinúa 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 tu dedo". Haz que los fotogramas intermedios apunten al resultado, no solo interpolen ciegamente hacia él.

9. Rubber-banding — límites suaves

En un borde, resiste progresivamente en lugar de detenerte bruscamente. Una parada brusca se lee como "congelado"; la resistencia continua se lee como "responde, pero no hay nada más aquí". Aplica 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 frenan antes de detenerse
function rubberband(overshoot, dimension, constant = 0.55) {
  return (overshoot * dimension * constant) / (dimension + constant * Math.abs(overshoot));
}

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

  • Toque: resalta al presionar (instantáneo), confirma al soltar. Agrega ~10px de histéresis/relleno de acierto alrededor del objetivo, y permite cancelar arrastrando hacia afuera y regresando.
  • Arrastre/deslizamiento: requiere un pequeño umbral de movimiento (histéresis, ~10px) antes de comprometerse con una dirección, luego rastrea 1:1.
  • Detecta todos los gestos plausibles en paralelo desde el primer movimiento, luego cancela con confianza los perdedores una vez que la intención está clara. Evita los reconocedores que solo informan un estado final (eventos tipo swipeleft) — tiran el seguimiento continuo que necesitas para la retroalimentación.
  • Minimiza los retrasos de desambiguación. La detección de doble toque inevitablemente retrasa los toques simples; solo paga ese costo donde realmente existe 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.

  • Mantén 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 estela nítida y dura.
  • requestAnimationFrame es el reloj sincronizado con la pantalla de la web (Apple usa CADisplayLink). Anima solo propiedades amigables para el compositor — transform y opacity — y sugiere con will-change donde el movimiento es 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, aproxima con backdrop-filter.

  • Construye navs/barras de herramientas/hojas como capas translúcidas (backdrop-filter: blur() + un fondo semitransparente) con contenido desplazándose debajo — no barras opacas que consumen 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 apiles una superficie translúcida clara sobre otra — la legibilidad se colapsa.
  • Las superficies más grandes deben leerse como más gruesas: un desenfoque más fuerte + una sombra más profunda que los chips pequeños. Considera la sombra consciente del contexto — más pesada sobre contenido ocupado/texto para separación, más clara sobre fondos lisos.
  • Atenúa para enfocar, separa 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 bloqueador usa translucidez y desplazamiento sin un velo para que no se rompa el flujo. Para hojas apiladas, atenúa progresivamente y empuja hacia atrás cada capa principal.
  • La vitalidad mantiene el texto legible sobre fondos cambiantes. Sobre superficies desenfocadas/translúcidas, no uses texto gris plano — usa un peso ligeramente más pesado, mayor contraste y un pequeño aumento en el espacio entre letras. Pon el color en una capa sólida, no en 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, desvanece una máscara de desenfoque/gradiente pequeña donde el contenido se encuentra con el cromo flotante, solo donde la interfaz de usuario flotante realmente se superpone al contenido.
  • Materializa, no solo desvanezcas. Para superficies de vidrio/desenfoque, anima 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 atrapa el material */
}

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

Tres reglas para combinar los sentidos (de Designing Audio-Haptic Experiences):

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

…

[truncado para la traducción]

Skills relacionados