wandres.dev
GSAP X · Plugins de SVG

shapeIndex, origin y el tipo de interpolación

Las opciones que arreglan un morfeo feo: el desplazamiento del emparejamiento, la interpolación rotacional con su origen, el mapeo de subcontornos y el suavizado.

⏱ 20 min

Cuando un morfeo se ve mal, la reacción típica es cambiar la duración o el ease, que no arregla nada porque el problema no es de tiempo sino de geometría. Las opciones que sí importan son cuatro, cada una ataca una causa distinta, y usarlas requiere primero diagnosticar qué está fallando. Esta lección es el manual de esas cuatro, con la herramienta interactiva que la propia documentación ofrece para no tener que adivinar valores.

🎯 Al terminar esta lección sabrás
  • Usar shapeIndex para corregir un emparejamiento desfasado, incluida su forma negativa.
  • Elegir entre interpolación lineal y rotacional y colocar bien el origin.
  • Ajustar el emparejamiento de subcontornos con map.
  • Añadir anclas de suavizado con smooth sin destruir la fidelidad del original.

shapeIndex: el desfase del emparejamiento

Todo contorno cerrado tiene un punto de partida: el sitio donde el lápiz empieza a dibujar. Si dibujas un círculo con un lápiz, puedes empezar en las doce, en las tres o en las nueve, y el resultado visual es idéntico pero la secuencia de puntos es distinta.

Cuando el origen empieza en un punto y el destino en otro, el emparejamiento primero-con-primero hace que la forma se retuerza. shapeIndex es el desplazamiento que corrige eso: shapeIndex: 3 empareja el tercer punto del origen con el primero del destino.

gsap.to("#cuadrado", { duration: 1, morphSVG: { shape: "#estrella", shapeIndex: 3 } });

Dos notas importantes. shapeIndex solo funciona en contornos cerrados, porque en uno abierto el punto de partida está determinado. Y un valor negativo invierte además el sentido de recorrido del contorno de origen, que es exactamente lo que hace falta cuando las dos formas están dibujadas con sentidos de giro opuestos —una en el sentido de las agujas del reloj y otra al revés—, un caso muy frecuente si las formas vienen de programas de dibujo distintos.

Adivinar el número correcto es tedioso, así que la documentación ofrece una utilidad de desarrollo llamada findShapeIndex(), que se carga aparte y monta una interfaz interactiva donde ves el punto de partida, lo mueves y previsualizas el morfeo.

// Solo durante el desarrollo, con el script de la utilidad cargado
findShapeIndex("#cuadrado", "#estrella");

Y hay una variante útil para producción: si en lugar de un número pasas la cadena "log", el plugin se comporta como en modo automático pero además saca por consola el valor que ha calculado. Copias ese valor, lo pegas como número, y el plugin se ahorra el cálculo en cada ejecución.

// 1) Descubrir el valor que elige el modo automatico
gsap.to("#a", { duration: 1, morphSVG: { shape: "#b", shapeIndex: "log" } });

// 2) Fijarlo. Con varios subcontornos sale un array: shapeIndex: [5, 1, -8]
gsap.to("#a", { duration: 1, morphSVG: { shape: "#b", shapeIndex: [3] } });

type rotational y el origin

La segunda causa de un morfeo feo es distinta: la forma llega bien al destino pero por el camino aparecen picos donde el original tenía curvas suaves.

El motivo es que la interpolación por defecto, type: "linear", mueve cada ancla y cada manejador de control en línea recta desde su posición inicial a la final. Un ancla suave lo es porque sus dos manejadores están alineados; si ambos se mueven en línea recta hacia posiciones donde volverán a estar alineados, en los puntos intermedios pueden dejar de estarlo, y una alineación rota es visualmente un pico.

type: "rotational" interpola usando el ángulo y la longitud de los manejadores en lugar de sus coordenadas. Con eso, un manejador que rota de una posición a otra recorre un arco y mantiene la relación con su pareja, con lo que el ancla sigue siendo suave durante todo el trayecto.

gsap.to("#forma-a", {
  duration: 2,
  morphSVG: { shape: "#forma-b", type: "rotational" },
});

Con la interpolación rotacional aparece un parámetro nuevo: el centro de rotación. Por defecto es el centro de la caja, "50% 50%", y a veces produce giros que se ven raros. origin permite moverlo.

gsap.to("#forma-a", {
  duration: 2,
  morphSVG: {
    shape: "#forma-b",
    type: "rotational",
    origin: "20% 60%",
  },
});

Y admite una forma con cuatro valores cuando el origen adecuado del contorno inicial y el del final son distintos: origin: "20% 60%,35% 90%".

Igual que con shapeIndex, hay una utilidad de desarrollo, findMorphOrigin(), que superpone un marcador de origen arrastrable sobre el morfeo para que veas en directo cómo afecta.

Puedes cambiar el tipo por defecto para todo el proyecto:

MorphSVGPlugin.defaultType = "rotational";

Desde la versión 3.14 existe además curveMode: true, que ataca el mismo problema de los picos por otra vía: interpola el ángulo y la longitud de los manejadores manteniendo la posición de las anclas. La documentación advierte de que puede empeorar algunos morfeos, sobre todo cuando las anclas están muy juntas, así que es cuestión de probar ambos y quedarse con el que se vea mejor.

map: el emparejamiento de subcontornos

Cuando ambos paths tienen varios subcontornos, hay que decidir cuál va con cuál. map elige el criterio.

Valor Criterio
"size" Empareja por tamaño global, y usa la posición para desempatar. Es el valor por defecto y el que da resultados más intuitivos
"position" Empareja principalmente por proximidad
"complexity" Empareja por cantidad de anclas. Es el más rápido y permite forzar emparejamientos añadiendo anclas a mano en el programa de dibujo
gsap.to("#logo", { duration: 1, morphSVG: { shape: "#logo-b", map: "complexity" } });

"complexity" tiene un uso astuto que merece conocerse: si en tu editor de vectores le das a cada subcontorno del origen el mismo número de anclas que el subcontorno del destino con el que quieres emparejarlo, ese modo respeta tu decisión. Es una forma de meter información de correspondencia dentro del propio archivo SVG.

Y la recomendación oficial cuando ninguno de los tres funciona sigue siendo la misma: separa el path en varios elementos y morfea cada uno por su cuenta. Es más código y da control total.

smooth: añadir resolución

La cuarta opción, incorporada en la versión 3.14, ataca un problema distinto: formas cuyas anclas están mal repartidas. Si el origen tiene cuatro anclas concentradas en una esquina y el destino las tiene repartidas, la deformación se concentra donde hay puntos y el resto se mueve rígido.

smooth añade anclas de suavizado, como si subieras la resolución del contorno.

// Redibujar con 80 anclas equiespaciadas
gsap.to("#a", { duration: 1, morphSVG: { shape: "#b", smooth: 80 } });

// Elegir la cantidad automaticamente segun el area
gsap.to("#a", { duration: 1, morphSVG: { shape: "#b", smooth: "auto" } });

Y en su forma de objeto ofrece tres controles:

points es el número de anclas. redraw, activado por defecto, redibuja el contorno entero con anclas equiespaciadas, lo que reparte bien pero pierde algo de fidelidad respecto al dibujo original; con redraw: false se conservan las anclas originales y las nuevas se intercalan entre ellas, con fidelidad perfecta y reparto peor. persist, activado por defecto, deja la forma redibujada al terminar para evitar un salto visual al volver al original; con persist: false se retiran las anclas añadidas al acabar.

gsap.to("#diamante", {
  duration: 1,
  morphSVG: {
    shape: "#rayo",
    smooth: { points: 40, redraw: false, persist: false },
  },
});
⚠️
Más anclas no es siempre mejor

Cada ancla de suavizado es un punto más que interpolar en cada frame y una cadena d más larga que el navegador tiene que parsear y rasterizar. Con smooth: 300 sobre un icono sencillo estás pagando un coste considerable para arreglar un problema que probablemente no tenías. La documentación es explícita: normalmente no hace falta.

Las cuatro opciones son cuatro maneras de aportar información que el SVG no contiene, y por eso el orden de diagnóstico importa

Hay una forma eficiente de usar este catálogo y una forma que consume tardes enteras. La ineficiente es probar opciones al azar hasta que algo mejore. La eficiente parte de reconocer que cada opción repara una capa distinta del problema, y que esas capas están ordenadas: hay que resolver la de abajo antes de tocar la de arriba, porque si la correspondencia está mal, ninguna cantidad de suavizado ni de interpolación rotacional lo va a arreglar; solo hará que la forma se retuerza más suavemente. El orden correcto es el orden de la pila. Primero, ¿está emparejando los subcontornos correctos? Eso es map, y si no hay más que un subcontorno, sáltatelo. Segundo, ¿está emparejando los puntos correctos dentro de cada contorno? Eso es shapeIndex, y su síntoma —el retorcimiento— es tan característico que se reconoce a ojo. Tercero, ¿está la trayectoria de cada punto bien elegida? Eso es type y curveMode, y su síntoma son los picos temporales en curvas que deberían ser suaves. Cuarto y último, ¿hay suficiente resolución para que la deformación se reparta? Eso es smooth, y solo tiene sentido cuando los tres anteriores ya están bien. Lo interesante de esta jerarquía es que se corresponde exactamente con las decisiones que el algoritmo tuvo que tomar en ese orden al preparar el morfeo, así que estás depurando la tubería de arriba abajo, igual que se depura cualquier proceso por etapas. Y hay una quinta pregunta que a veces es la correcta y que ninguna opción responde: ¿es este morfeo el efecto adecuado? Dos formas sin ninguna relación estructural entre sí —un texto y un animal, un logotipo y un icono— no tienen un morfeo natural porque no hay correspondencia que descubrir, y ninguna configuración va a inventarla. Ahí lo que quieres es un cruce con desvanecido, o dos animaciones separadas, no una interpolación.

⚔️ Diagnosticar antes de ajustar
  1. Provoca a propósito un morfeo retorcido entre dos contornos cerrados y arréglalo con shapeIndex, usando primero "log" para descubrir el valor.
  2. Coge dos formas dibujadas con sentidos de giro opuestos y comprueba que solo un shapeIndex negativo lo arregla.
  3. Morfea dos formas con curvas suaves usando type: "linear" y luego "rotational", y busca los picos intermedios en la primera.
  4. Mueve el origin de un morfeo rotacional a tres posiciones distintas y describe cómo cambia la trayectoria.
  5. Prueba los tres valores de map sobre un logotipo de tres piezas y anota cuál empareja como esperabas.