Communitygithub.com

grahama1970/apple-design

El enfoque de Apple para el diseño de interfaces y el movimiento físico fluido, traducido para la web. Úselo al construir o revisar interfaces impulsadas por gestos, animaciones con resorte, interacciones de arrastre/deslizamiento/hoja, transiciones con impulso 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 apple-design?

Este skill proporciona una guía completa y detallada sobre cómo implementar principios de diseño de interfaces fluidas al estilo Apple en la web. Se basa en conceptos de las charlas de diseño de WWDC, principalmente 'Designing Fluid Interfaces' (WWDC 2018), y los traduce a tecnologías web prácticas como CSS, Pointer Events, requestAnimationFrame y librerías de resorte como Motion y Framer Motion. El núcleo de la filosofía es que una interfaz se siente viva cuando el movimiento comienza desde el valor actual en pantalla, hereda la velocidad del usuario, proyecta el impulso hacia adelante y se puede agarrar e invertir en cualquier instante. Cubre catorce principios clave, desde la respuesta inmediata y la manipulación directa hasta la interrumpibilidad, el uso de resortes en lugar de animaciones de duración fija, el traspaso de velocidad, la proyección de momento, la coherencia espacial y el diseño de gestos. También aborda aspectos avanzados como materiales translúcidos, profundidad, retroalimentación multimodal, movimiento reducido y accesibilidad. Es adecuado para plataformas como Claude Code, Cursor y Codex, y está diseñado para desarrolladores que buscan crear interfaces web con una sensación de fluidez, capacidad de respuesta y tacto físico similares a las de Apple.

Compatible con~Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/grahama1970/agent-skills/tree/main/skills/apple-design

Preguntar en tu IA favorita

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

Documentación

Diseño Apple

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 la WWDC de Apple — principalmente Designing Fluid Interfaces (WWDC 2018) — destilado y traducido para la plataforma web (CSS, Pointer Events, requestAnimationFrame, librerías 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 impulso hacia adelante y se puede agarrar e invertir 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 impulso, resisten en los límites y se pueden redirigir en medio del movimiento. Todo lo que sigue es una forma de acercarse a eso.

Apple enmarca el diseño como el servicio de 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 "cae 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 al evento click/levantar el dedo para mostrar retroalimentación se siente muerto.
  • Vigila 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 UI 1:1 con el puntero durante todo el proceso — nunca animes solo cuando el gesto se complete.
/* La retroalimentación vive en la presió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.

  • Usa Pointer Events con setPointerCapture para que el seguimiento continúe incluso cuando el puntero sale de los límites del elemento.
  • Mantén 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
  // ...registra 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. El usuario debe poder agarrar un elemento en movimiento a medio vuelo e invertirlo sin esperar a que termine la animación. Un modal que se cierra y que el usuario vuelve a agarrar debe seguir el dedo — no terminar de cerrarse primero y luego reabrirse.

  • Nunca bloquees la entrada durante una transición.
  • Anima siempre desde el valor de presentación (actual), nunca desde 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 provoca 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 librerías de resortes que arrastran la velocidad a través de un reajuste lo evitan. (Esto es lo que las animaciones aditivas de iOS hacen de forma nativa; en la web, elige una librería de resortes que reajuste desde la velocidad actual).
  • Descompón el movimiento 2D en resortes independientes para X e Y. 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 preprogramada y de duración fija no puede responder a nuevas entradas. Un resorte puede — 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 de física (masa/rigidez/amortiguamiento) con dos parámetros amigables para el diseñador. Piensa en estos:

  • Relación de amortiguamiento (damping ratio) — controla el sobreimpulso. 1.0 = críticamente amortiguado, sin rebote, asentamiento suave. < 1.0 = sobrepasa y oscila. Menor = más saltarín.
  • Respuesta (response) — qué tan rápido el valor alcanza el objetivo, en segundos. Menor = más rápido. 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 UI con amortiguamiento 1.0 (críticamente amortiguado) — elegante y no distractivo.
  • Añade rebote (amortiguamiento ~0.8) solo cuando el gesto en sí mismo llevaba impulso (un movimiento rápido, un lanzamiento, una liberación de arrastre). Un sobreimpulso en un menú que simplemente apareció se siente mal; un sobreimpulso en una tarjeta que lanzaste se siente bien.

Valores concretos que Apple envía:

InteracciónAmortiguamientoRespuesta
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 mapea cercanamente al amortiguamiento + respuesta de Apple. Un estilo base seguro es 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';

// Predeterminado críticamente amortiguado (sin sobreimpulso)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });

// Interacción con 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 "correcto".

Pasa la velocidad de liberación del puntero como la velocidad inicial del resorte. Algunas APIs de resortes quieren una 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 la velocidad absoluta en px/s directamente (opción velocity), por lo que generalmente le pasas el valor sin procesar.

6. Proyección de momento — anima hacia donde se dirige el gesto

"Toma una pequeña entrada y haz 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 — y 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 Designing Fluid Interfaces):

// decelerationRate ≈ 0.998 para 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);   // 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 carruseles (Vaul, Embla).

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

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

  • Entra y sale por el mismo camino. Un panel que se desliza desde la derecha debe descartarse hacia la derecha. Entrar desde la derecha / salir por abajo se siente desconectado y confuso.
  • Ancla las interacciones a su origen. Un menú, popover o hoja debe originarse desde el elemento que lo desencadenó — establece transform-origin al desencadenante, para que la relación espacial entre el botón y el contenido sea obvia. (Este es el mismo punto de conciencia de origen que los popovers escalando desde su desencadenante, no desde su centro).
  • Refleja la aceleración en transiciones reversibles para que el camino de salida coincida con el camino de retorno (usa puntos de control cúbico-bezier inversos para las dos direcciones).

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

9. Bandas de goma (Rubber-banding) — límites suaves

En un borde, resiste de forma progresiva en lugar de detenerte bruscamente. Una parada brusca se lee como "congelado"; una resistencia continua se lee como "responsive, pero no hay nada más aquí". Aplica un amortiguamiento 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 del diseño de gestos (la lista de verificación de "sensación")

  • Toque: resalta al bajar el toque (instantáneo), confirma al levantar el toque. Añade ~10px de histéresis/relleno de acierto alrededor del objetivo, y permite cancelar arrastrando hacia afuera y volviendo.
  • 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) — descartan el seguimiento continuo que necesitas para la retroalimentación.
  • Minimiza las demoras de desambiguación. La detección de doble toque inevitablemente retrasa el toque simple; 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 posicional por fotograma por debajo del umbral de percepción para evitar el efecto estroboscópico.
  • Para movimientos muy rápidos, un sutil desenfoque de movimiento / estiramiento codifica la velocidad y se lee mejor que una línea dura y nítida.
  • requestAnimationFrame es el reloj sincronizado con la pantalla de la web (Apple usa CADisplayLink). Anima solo propiedades amigables con el compositor — transform y opacity — e indica 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 foco. En la web, aproxima con backdrop-filter.

  • Construye barras de navegación/herramientas/hojas como capas translúcidas (backdrop-filter: blur() + un fondo semitransparente) con contenido que se desplaza 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 ligeros 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 sombras sensibles al contexto — más pesadas sobre contenido ocupado/de texto para separación, más ligeras sobre fondos simples.
  • Atenúa para enfocar, separa para mantener el flujo. Una tarea modal empareja la superficie con una cortina de atenuación y empuja el fondo hacia atrás/abajo. Un panel paralelo y no bloqueante usa translucidez y desplazamiento sin una cortina para que el flujo no se rompa. Para hojas apiladas, atenúa y empuja hacia atrás progresivamente cada capa principal.
  • La vitalidad (vibrancy) mantiene el texto legible sobre fondos cambiantes. Sobre superficies translúcidas/desenfocadas, no uses texto gris plano — usa un contraste más alto, un peso ligeramente mayor y un pequeño aumento en el espaciado 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 pequeña máscara de desenfoque/gradiente donde el contenido se encuentra con el cromo flotante — solo donde la UI 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 simple desvanecimiento de opacidad.
.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 incidiendo en el material */
}

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

Tres reglas para combinar 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 cambia, 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 una transición CSS retrase el audio/háptico (API de Vibración).
  3. Utilidad — añade retroalimentación solo donde se gane su lugar. Reserva háptica/sonido para momentos significativos (éxito, error, compromiso, ajuste). El exceso de retroalimentación entrena al usuario a ignorarla toda.

14. Movimiento reducido y accesibilidad

Movimiento reducido no significa sin retroalimentación — significa que la retroalimentación no debe ser disruptiva. Usa la consulta de medios prefers-reduced-motion de CSS para detectar la preferencia del sistema por movimiento reducido. Cuando esté activa:

  • Reemplaza las animaciones basadas en movimiento con transiciones de opacidad simples y cortas.
  • Evita escalados, traslaciones y animaciones de desenfoque que podrían causar molestias.
  • Asegúrate de que toda la información transmitida a través del movimiento (como el estado de arrastre o el enfoque) también esté disponible de forma estática.
  • Mantén las animaciones funcionales, como las que indican carga o progreso, pero hazlas sutiles y no distractivas.
@media (prefers-reduced-motion: reduce) {
  .animated-element {
    transition: opacity 150ms ease-out;
    transform: none !important;
  }
}

La accesibilidad no es una ocurrencia tardía; es parte integral del diseño. Un diseño fluido debe ser utilizable y comprensible para todos, independientemente de sus capacidades motoras, visuales o cognitivas.

Conclusión

Los principios de diseño de Apple para interfaces fluidas son un conjunto de pautas que priorizan la sensación de inmediatez, control y naturalidad. Al implementarlos en la web, es crucial adaptarlos a las capacidades y limitaciones de la plataforma, pero el espíritu permanece: una interfaz debe sentirse como una extensión del usuario, respondiendo a sus acciones de manera predecible, suave e interrumpible. Desde la respuesta instantánea hasta la transferencia de velocidad y la proyección de momento, cada detalle contribuye a esa sensación mágica de que el software desaparece y solo queda la interacción humana.

Individual skills in this repo

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

grahama1970/acceptance-contract

Turn a client brief, zip bundle, directory, or single requirements file into a typed acceptance-contract bundle with extracted requirements, acceptance checks, open questions, an immutable-goal draft, and a create-report-backed decision report. Use when users say acceptance contract, brief to requirements, freeze the goal, create immutable goal, amend immutable goal, build a Battle requirements bundle, or extract requirements from this bundle.

grahama1970/agent-ecosystem

Canonical map and shared contracts for the agent-governance ecosystem: the pi.receipt_envelope.v1 boundary envelope, the component graph, and the rules for which component owns which schema. Use when wiring a skill or extension into the shared receipt world, when asking how shame, triage-error, tau, ask, project-watchdog, ops-herdr, ponytail, and Memory fit together, or when validating an envelope.

grahama1970/agentic-evals

Agentic evaluation of skills using multi-trial fixtures, deterministic command assertions, trajectory checks, safety constraints, and evidence-backed readiness scoring. Use when users ask for agentic evals, multi-trial skill evaluation, skill trajectory validation, or readiness scoring for a skill workflow.

grahama1970/agent-inbox

File-based inter-agent messaging with headless dispatch. Check inbox, send bugs/requests to other projects, automatically spawn headless agents to fix bugs, and track progress via task-monitor.

grahama1970/agents-registry

Generate and query the centralized agent identity registry. Scans .pi/agents/*/AGENTS.md, parses frontmatter, outputs agents-registry.json and optionally syncs to /memory for semantic search.

grahama1970/agent-status

Artifact-driven status surfaces for long-running project-agent work. Maintains status.json, events.jsonl, proof manifests, and a stale-aware STATUS.html so humans can tell where the agent is, what passed, what is still unproven, and what decision or action is next — without dashboard theater.

grahama1970/align

Round-based context alignment before execution. Use when the human, project agent, WebGPT, scillm, ask, dogpile, memory, or project-knowledge may each hold different facts about a task; especially before ambiguous design, infographic, product workflow, high-stakes implementation, plan-iterate, project-infographic, or multi-review work.

grahama1970/analytics

Flexible data science analytics for any dataset. Auto-discovers schema, recommends charts, exports to create-figure. Works with JSONL, JSON, CSV from any source.

grahama1970/analyze-chatterbox-emotions

Evaluate generated Chatterbox voice files as voice-quality artifacts: affect match, arousal/valence proxies, pause placement, intelligibility inputs, clipping, loudness, and discontinuity flags. Use when reviewing Chatterbox emotional tags, pauses, Turbo/base affect delivery, Persona Dream utterance renders, or whether generated speech matches an intended product-facing affect.

grahama1970/analyze-elf

Reverse-engineer features from ELF binaries. Extracts CLI commands, state machines, protocols, Zod schemas, and data models. Automatically generates a /create-walkthrough prosecution brief with Mermaid diagrams. Uses /treesitter for AST analysis of bundled JS/TS source.

grahama1970/animation-vocabulary

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.

grahama1970/anonymize-data

Anonymize supported CSV, JSON, UTF-8 text, and SQLite files using an explicit policy through the oai-trial project. Use for anonymize data, pseudonymize exports, redact policy literals, or discover and explicitly approve fuzzy name aliases. The skill is a thin CLI/Docker interface, not another engine.

grahama1970/anvil

Heavy-duty "No-Vibes" debugging and hardening orchestrator. Use this for complex, stubborn bugs where `review-code` has failed, or for "Red Teaming" (hardening) a codebase. Runs multiple agents in parallel (Thunderdome) using git worktree isolation.

grahama1970/argue

Multi-persona structured debate orchestrator. Personas research via /dogpile, consult colleagues via /ask, and argue toward nuanced synthesis on complex questions.

grahama1970/arxiv

Search arXiv for papers and extract knowledge into memory. Use `search` to find papers, `learn` to extract knowledge.

grahama1970/ask

Use when the user asks to query project memory, ask an oracle, use supported browser-backed reviewers, run Tau roundtable/single-handler workflows, ask Pi-native subagents from within Pi, run persona/deep-review workflows, generate image prompts, check OS/project health through composed skills, or run an ask DAG. This skill is the executable /ask runtime; do not replace it with an informal subagent, plain web search, or hand-written review; inside Pi, explicit Pi-native subagent targets are routed through the pi-subagents tool as an Ask target type.

grahama1970/assess

Step back and critically reassess project state. Use when asked to "assess", "step back", "fresh eyes", "check alignment", "sanity check", "health check", "prune documentation", or "evaluate what's working". Offers documentation pruning and doc-code alignment analysis. Offer to run after major changes (don't auto-run).

grahama1970/assistant

Shared GPT + classifier inference gateway for persona monitor tasks. Routes validation and classification through a 4-tier cascade: heuristic → classifier → local GPT → scillm.

grahama1970/assistant-lab

Self-improvement workbench for /assistant. All the tools needed to diagnose, train, evaluate, and promote models in a continuous loop. The "warm pond" where /assistant evolves its own inference stack.

grahama1970/batch-quality

Pre-flight validation and quality gates for batch LLM operations. ACTUALLY tests samples through LLM before burning tokens. Uses SPARTA contracts for DuckDB validation queries. Integrates with task-monitor for enforced quality gates.

Skills relacionados