Communitygithub.com

pafelab/stretchy-morph-ui

Convierte interfaces web en UI flexibles y elásticas, donde las transiciones se estiran, comprimen, sobrepasan y se estabilizan con resortes en lugar de curvas de easing.

¿Qué es stretchy-morph-ui?

Este skill transforma interfaces de usuario web en experiencias animadas y elásticas, donde cada cambio de estado se siente como un material vivo que se estira, comprime y oscila. Utiliza un motor de resortes físicos en lugar de curvas de easing tradicionales para lograr transiciones naturales y receptivas. El skill incluye: un motor de resortes completo, 24 componentes de referencia funcionales, un escáner para auditar el código del usuario, un verificador de navegador, y un método para inventar nuevos componentes elásticos. Es compatible con plataformas como Claude Code, Cursor y Codex, y está diseñado para trabajar con cualquier código HTML/CSS/JS existente. El flujo de trabajo comienza auditando el código del usuario para identificar componentes que puedan volverse elásticos (pestañas, botones, modales, acordeones, etc.), luego solicita confirmación antes de realizar cualquier edición. El motor de resortes utiliza osciladores armónicos amortiguados con integración semi-implícita, respeta preferencias de movimiento reducido y permite ajustar la elasticidad global con un solo control.

Compatible con✓Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/pafelab/stretchy-morph-ui/tree/HEAD

Preguntar en tu IA favorita

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

Documentación

Interfaz de usuario elástica (Stretchy morph UI)

Este skill produce interfaces donde cada cambio de estado se transforma: un indicador de pestaña se estira como un gusano en camino a la siguiente pestaña, un botón se comprime en un círculo de carga y se expande de nuevo, una imagen de producto se levanta de su tarjeta, se encoge hasta convertirse en un chip y cae en el carrito. Se destiló a partir de la construcción de una muestra de 24 componentes (en assets/showcase.html) y los errores y correcciones de diseño encontrados en el camino.

El aspecto proviene de una idea: el estiramiento tiene una causa. Un elemento se deforma porque sus partes no están de acuerdo (un borde llega antes que el otro), porque se mueve rápido (se alarga a lo largo de su trayectoria), porque está siendo comprimido (se abulta en la otra dirección para mantener su volumen), o porque acaba de ser golpeado (oscila). Un bamboleo aleatorio en bucle se ve barato; un estiramiento con causa parece material.

Paso 0, cada vez: audita el código del usuario y confirma

Antes de construir o editar cualquier cosa, descubre qué partes de la interfaz del usuario pueden volverse elásticas y permite que el usuario elija. Los detalles, criterios de juicio y plantillas de mensajes están en references/audit.md; la versión resumida:

  1. Encuentra el código: código pegado, archivos adjuntos (en claude.ai, lista /mnt/user-data/uploads), el directorio de trabajo o repositorio, un enlace de artefacto (léelo con la herramienta de artefactos), o una fuente que el usuario indique. Si no hay ninguno, di lo que buscaste y ofrece dos caminos: compartir el código, o construir algo nuevo desde cero.
  2. Escanea: python scripts/audit_ui.py <paths> informa sobre el stack, el movimiento existente, la gestión faltante de movimiento reducido, y candidatos por categoría de UI con archivo:línea, cada uno mapeado a un componente de muestra y técnica.
  3. Lee cada acierto en contexto y conserva solo los candidatos reales. Para cada uno, anota dónde está, qué ocurre ahora, la frase de transformación que sería, el esfuerzo (pequeño, mediano, grande) y cualquier riesgo (marcado de biblioteca de componentes, una biblioteca de animación existente, un control nativo cuyo selector móvil se perdería, listas muy largas).
  4. Prioriza por visibilidad × frecuencia × ajuste, agrupa duplicados (todos los botones que usan un Button compartido son un solo elemento), limita la lista a unos diez, y enumera cualquier cosa que aconsejes en contra con el motivo.
  5. Pide confirmación en el idioma del usuario: las propuestas numeradas, luego una pregunta que invite a elegir números, tomar todas las recomendadas, o escribir partes adicionales que quieran elásticas que no estén en la lista. Usa una herramienta de opciones seleccionables si el entorno la tiene, si no, texto plano. Termina el turno aquí; no hagas ediciones antes de la respuesta.
  6. Construye lo que eligieron más cualquier cosa que añadieron, luego sigue el Flujo de trabajo a continuación e informa por cada elemento.

Si el usuario ya nombró las partes que quiere, aún así audita: pon sus partes primero, ofrece el resto como opcional, y mantén la pregunta breve.

Archivos

Todas las rutas son relativas a la carpeta de este skill (la carpeta que contiene este SKILL.md), no al proyecto del usuario. Resuélvelas contra la carpeta del skill cuando las leas o ejecutes.

RutaQué esCuándo abrirlo
assets/stretchy-core.jsEl motor de resortes más ayudantes (pares de bordes, indicador segmentado, escala de volumen, bordes SVG abultados, reordenamiento FLIP, objetos lanzados)Pega en cada página que construyas. Léelo una vez para conocer los ayudantes.
assets/starter.htmlEsqueleto de página: tokens claro/oscuro, fuente variable con capacidad tailandesa, gestión de movimiento reducido, el núcleo incrustado, un componente de ejemploComienza una página nueva desde aquí
assets/showcase.htmlLos 24 componentes funcionales de la construcción original. Cada sección JS comienza con un banner como /* ---------- pestañas ---------- */Cuando una solicitud coincide con un componente del catálogo, usa grep -n "/\\* ---------- " assets/showcase.html y lee solo esa sección más su CSS
references/audit.mdCómo encontrar, escanear, juzgar y priorizar el código del usuario, y las plantillas de mensajes de confirmación (tailandés e inglés)En el Paso 0, cada vez
references/techniques.mdLas 11 técnicas de estiramiento en profundidad, con código y números de ajusteAntes de construir algo que no hayas construido antes
references/components.mdCatálogo: receta de cada componente, valores de resortes y errores comunesCuando la solicitud nombre o se parezca a un componente del catálogo
references/new-components.mdCómo diseñar una versión elástica de cualquier componente, más 14 diseños desarrollados que no están en la muestraSiempre que la solicitud esté fuera del catálogo
scripts/audit_ui.pyEscáner para el código del usuario: stack, movimiento existente y candidatos elásticos con archivo:líneaEn el Paso 0, cada vez
scripts/check_page.pyVerificación de navegador sin cabeza: errores JS, desbordamiento lateral en móvil y escritorio, elementos invisibles que roban clics, y hojas de contacto de fotogramas de animaciónDespués de cada construcción, antes de entregar cualquier cosa

Si hay disponible un skill de diseño visual (por ejemplo frontend-design o ui-ux-pro-max), léelo también. Ese skill decide cómo se ve la página (paleta, tipografía, diseño); este decide cómo se mueve. El pulido del movimiento no puede rescatar una página de aspecto genérico.

Flujo de trabajo (después de la confirmación del usuario)

  1. Escribe la frase de transformación para cada componente. "Cuando disparador, forma A se convierte en forma B, y se estira porque causa." Ejemplo: "Cuando se hace clic en una pestaña, el indicador se mueve hacia ella, y se estira porque su borde delantero es más rígido que su borde trasero." Si no puedes completar la causa, elige una de la tabla a continuación. Esta frase es el diseño; todo lo demás es implementación.
  2. Elige la(s) técnica(s) de la tabla. La mayoría de los componentes usan un estiramiento principal más un pequeño bamboleo de retroalimentación.
  3. Define los estados de reposo como números: anchos, altos, radios, posiciones, progreso de 0 a 1. Los resortes animan números y los escribes en style en onUpdate. Las transiciones CSS manejan solo color y opacidad (y fundidos cruzados de contenido corto).
  4. Planifica el contenido. El texto y los iconos no deben refluir ni aplastarse mientras el contenedor se transforma. Dale a cada estado de contenido su propia capa en su tamaño final, anclada (generalmente centrada), y haz un fundido cruzado: salida rápida (≈150 ms), entrada después de un retraso de ≈100–150 ms con una ligera escala o desenfoque. El overflow:hidden del contenedor revela el contenido a medida que crece.
  5. Construye desde assets/starter.html con el núcleo incrustado. Escribe los estilos directamente en las devoluciones de llamada del resorte; nunca desencadenes un re-renderizado del framework por fotograma.
  6. Pase de accesibilidad e interrupción (lista de verificación a continuación).
  7. Prueba y observa. Ejecuta scripts/check_page.py, luego captura hojas de contacto de fotogramas de las interacciones importantes y míralas realmente. La animación de agregar al carrito en la construcción original "funcionaba" pero se veía barata hasta que se inspeccionaron los fotogramas; las correcciones están en "Cómo hacer que se vea bien".

De dónde viene el estiramiento

SituaciónTécnica (detalles en references/techniques.md)Visto en
Algo se mueve entre ranurasPar de bordes: dos resortes para bordes delantero y trasero, el delantero rígido, intercambiados por direcciónPestañas, puntos de carrusel, conmutadores, chips de elección, punto de radio, stepper, resaltado de desplegable, cápsula de calificación, navegación de barra lateral
Un contenedor cambia de tamaño o formaEjes divididos: resortes separados para ancho, alto, radio con diferente rigidez, para que un eje lidereIsla dinámica, FAB a formulario, modal desde botón, desplegable, botón de agregar al carrito
Algo se vuelve más estrecho o ancho rápidamentePreservación de volumen: escala el otro eje por velocidad, scaleY = clamp(1 − v/k)Botón de enviar, campo de búsqueda, ancho de desplegable
Algo viaja rápidoEstiramiento por velocidad: alargar en la dirección del movimiento, adelgazar a través de élPulgar de deslizador, elemento de carrito lanzado, tarjetas de carrusel (sesgado), tooltip
Una superficie grande se mueveBorde abultado: dibujar la superficie como una ruta SVG cuyo punto de control de borde está desplazado por −velocidadBarra lateral, hoja inferior
Una parte cuelga de una parte en movimientoSeguidor rezagado: un resorte más suave persigue al principal; usa el espacio para inclinación o desplazamientoBurbuja de valor de deslizador, texto interno de acordeón
Retroalimentación para un toque o llegadaPatada: añadir velocidad a un resorte en reposo en 0, oscila y se estabilizaCasilla de verificación, chips, carrito, estrellas, insignia, sacudida de límite de cantidad
Las burbujas se unen o dividenFiltro Goo: desenfoque más umbral alfa, fuente nítida compuesta encimaMenú Goo
Un elemento se convierte en un elemento diferenteTransformación de contenedor: comenzar en el rectángulo del disparador, saltar al rectángulo objetivo, fundido cruzado de contenidoModal, FAB, lanzamiento al carrito
El cambio necesita una pausa en medioTransformación secuenciada a través de una forma intermedia que tenga significado (spinner, check)Botón de enviar, botón de agregar al carrito
Arrastrar más allá de un límite, o una lista se reordenaBanda elástica (dividir el desbordamiento por ≈3) y FLIP con resortes que mantienen la velocidadCarrusel, hoja, lista de productos ordenada

El motor en un párrafo

Spring es un oscilador armónico amortiguado integrado con Euler semi-implícito en 8 sub-pasos por fotograma (delta de fotograma limitado a 1/30 s para que una pestaña en segundo plano no pueda explotarlo). to(target) redestina sin reiniciar la velocidad, que es lo que hace que los clics rápidos se sientan continuos en lugar de reiniciarse. set(x) salta sin animación, drag(x, v) sigue un puntero mientras registra la velocidad, kick(v) inyecta un impulso. El amortiguamiento se multiplica por un factor global bounce en cada tic, de modo que un control a nivel de página (suave 1.8, saltarín 1, elástico 0.5) reajusta cada componente en vivo. Bajo prefers-reduced-motion: reduce, to() salta al objetivo y dispara onRest inmediatamente, para que la lógica que espera una animación aún se ejecute.

Relación de amortiguamiento ζ = c / (2√k). Los cambios de estado de UI se sienten correctos alrededor de ζ 0.6–0.8; retroalimentación juguetona en 0.3–0.5; por encima de 1 nada sobrepasa. Los preajustes utilizados en la muestra:

RolkcNotas
Borde delantero de un par de bordes420–52030–34Llega primero
Borde trasero140–17017–19Se retrasa, lo que crea el estiramiento
Ancho del contenedor (transformación)240–32018–24
Alto del contenedor (transformación)150–17015–17Más lento que el ancho, por lo que la forma se estira lateralmente primero
Seguidor de puntero (deslizador)65042Ajustado, pero aún tiene velocidad para leer
Seguidor rezagado (burbuja)15011Suelto a propósito
Retroalimentación de patada380–42012–16Patada con 6–10
Alto con sobrepaso visible (acordeón)21014

Reglas prácticas

  • Limita cada deformación. Controles: preservación de volumen dentro de ±7–15 %. Cosas pequeñas y rápidas (un chip lanzado, un pulgar de deslizador): hasta 35–70 % de estiramiento. Siempre limita los tamaños a un mínimo positivo, ya que un resorte subamortiguado puede subestimar por debajo de cero.
  • Intercambia la rigidez por dirección. En un par de bordes, el borde que mira hacia la dirección del viaje recibe el resorte rígido. Sin el intercambio, el indicador se estira correctamente en una dirección y se comprime en la otra.
  • Tiempo opuesto en el camino de regreso. Si el ancho lidera la altura al abrir, deja que la altura lidere el ancho al cerrar. La forma entonces retrocede por un camino diferente, lo que se lee como elástico en lugar de un rebobinado.
  • Resortes para cambios de estado, curvas basadas en tiempo para caminos cuya forma importa. Un objeto lanzado necesita un arco predecible (Bézier cuadrático, progreso ease-in-out, alrededor de 800 ms). Los resortes x/y independientes dan caminos errantes. Deriva el estiramiento de la velocidad fotograma a fotograma de cualquier manera.
  • Mantén el contenido erguido. Para estirar algo a lo largo de una dirección arbitraria sin rotar su imagen o texto, usa rotate(a) scale(1+s, 1−s·0.45) rotate(−a).
  • Un movimiento audaz por componente. El resto del componente permanece tranquilo: un cambio de color, un fundido corto.
  • Calma cuando está inactivo. Nada oscila por sí solo. Como máximo un momento orquestado al cargar la página (la muestra abre la isla una vez después de 900 ms).

Cómo hacer que se vea bien (lecciones de la construcción)

La primera versión de agregar al carrito volaba una bola de color plano a lo largo de dos resortes independientes, encogía el botón en un óvalo violeta vacío y aplastaba el carrito. El usuario dijo que no era bonito. Lo que lo arregló se generaliza:

  • Mueve lo real. Clona la imagen del producto, levántala ligeramente con una sombra, luego encógela en un chip redondo que aún muestre la imagen mientras vuela. Los puntos abstractos se leen como salida de depuración.
  • Las formas intermedias deben tener significado. Un botón encogido es una burbuja vacía a menos que muestre algo: un spinner, una marca que se dibuja sola, un contador. El botón de agregar ahora se convierte en un círculo verde con una marca, luego crece hasta convertirse en el stepper − n +.
  • Volumen sutil en los controles. Un abultamiento vertical de ±18 % en un botón parecía un huevo en forma de píldora. ±7 % se lee como material suave.
  • La llegada necesita un receptor. El icono del carrito se inclina y se inclina, un anillo pulsa hacia afuera, la insignia aparece. Algo debe atrapar visiblemente lo que fue lanzado.
  • No recortes las marcas de estado. Una insignia dentro de una píldora con overflow:hidden que se transforma se corta; colócala en un envoltorio fuera del clip.
  • No repitas información. La píldora del carrito mostraba "3 ชิ้น 195 บาท" junto a una insignia que decía 3. Ahora muestra solo el total.
  • Dibuja las ilustraciones con una relación de aspecto fija. Las formas CSS posicionadas en porcentaje dentro de un mosaico se estiran cuando el mosaico se ensancha. Usa un SVG en línea con un viewBox, centrado en el mosaico.

Lista de verificación de accesibilidad y robustez

  • Respeta el movimiento reducido (el núcleo lo hace; asegúrate de que las keyframes y transiciones CSS también se corten en una consulta de medios prefers-reduced-motion).

  • Usa button, input, role="switch", role="tab", role="slider" reales, etc., con el estado aria-* correcto, actualizado en la misma llamada que inicia la animación.

  • El contenido oculto por una transformación recibe inert (y no debe interceptar clics: da a las capas invisibles pointer-events:none, luego actívalo de nuevo con el estado visible).

  • Mueve el foco deliberadamente cuando el control enfocado desaparece en una transformación: al control de reemplazo, de regreso al disparador después de que se cierra un diálogo, y solo después de que el elemento sea visible nuevamente (un elemento con visibility:hidden no puede recibir foco).## Notas de implementación

  • El archivo assets/stretchy-core.js exporta Spring y ayudantes como funciones globales. Inclúyelo en el <head> de tu página.

  • Usa requestAnimationFrame para el bucle de animación; el motor lo maneja internamente si está presente.

  • Para componentes con múltiples estados, usa un único Spring por propiedad animada y actualiza el estado de la UI en onUpdate.

  • Prueba en navegadores reales; el verificador de navegador (scripts/check_page.py) detecta errores comunes.

Ejemplo de flujo de trabajo

  1. El usuario dice: "Haz que mis pestañas sean elásticas".
  2. Ejecutas python scripts/audit_ui.py . para escanear el código.
  3. Encuentras pestañas en index.html:45 y propones: "1. Pestañas: el indicador se estira con par de bordes".
  4. El usuario confirma.
  5. Abres assets/starter.html, copias el esqueleto, incrustas assets/stretchy-core.js.
  6. Lees la sección de pestañas en assets/showcase.html para la técnica.
  7. Implementas: un Spring para el borde izquierdo, otro para el borde derecho, con rigidez intercambiada por dirección.
  8. Actualizas los roles ARIA y añades prefers-reduced-motion.
  9. Ejecutas scripts/check_page.py y corriges cualquier error.
  10. Entregas el resultado.

Este skill está diseñado para ser utilizado con plataformas de agentes de IA como Claude Code, Cursor o Codex. Sigue el flujo de trabajo descrito para obtener los mejores resultados.

Skills relacionados