Animación

Sistema de animación avanzado para crear animaciones dinámicas, procedimentales y basadas en expresiones más allá de simples fotogramas clave.

Tipos de Animación

El sistema de animación admite varios tipos más allá de los fotogramas clave tradicionales:

  • Expresión: Expresiones de JavaScript evaluadas por fotograma
  • Procedimental: Patrones de animación procedimentales incorporados
  • Secuencia: Animaciones secuenciales basadas en pasos
  • Ruta: Movimiento a lo largo de rutas de Bezier

Estas animaciones avanzadas se definen en la propiedad de array animations de los elementos.

Animaciones de Nodo vs Fotogramas Clave

Animaciones de Nodo (array animations):

  • Animaciones procedimentales, basadas en expresiones o que siguen una ruta
  • Evaluadas cada fotograma
  • Mayor prioridad que los fotogramas clave
  • Pueden sobrescribir los valores de los fotogramas clave

Fotogramas Clave (array keyframes):

  • Interpolación simple de propiedades entre puntos definidos
  • Menor prioridad
  • Predecible, fácil de editar

Prioridad de Animación

Cuando múltiples métodos de animación apuntan a la misma propiedad:

  1. Más Alto: Animaciones de nodo (expresión, procedimental, ruta, secuencia)
  2. Medio: Animaciones de fotogramas clave
  3. Más Bajo: Valores de propiedades estáticas
PropTipoRequeridoEjemploRango de ValoresDescripción
typestringtrue-expression | procedural | sequence | pathEl tipo de animación.
enabledbooleanfalse--Si la animación está activa.
targetstringtrue--La ruta de propiedad a animar (por ejemplo, "x", "rotation", "scaleX").
startTimenumberfalse--Tiempo de inicio de la animación relativo al inicio del elemento, en segundos.
durationnumberfalse--Duración de la animación en segundos. Para animaciones en bucle, este es el período de bucle.
loopbooleanfalse--Si la animación se repite.
blendModestringfalse-replace | add | multiplyCómo se combina esta animación con otras: reemplazar (sobrescribir), sumar (suma), multiplicar (escalar).
blendWeightnumberfalse--La fuerza/influencia de esta animación (0-1). Utilizado para mezclar múltiples animaciones.

Animaciones de Expresión

Las expresiones son código JavaScript evaluado por fotograma, con acceso a variables de contexto de animación.

Variables de Contexto Disponibles

{
  time: number; // Tiempo absoluto actual (segundos)
  localTime: number; // Tiempo relativo al inicio del elemento
  duration: number; // Duración del elemento
  progress: number; // Progreso normalizado (0-1)
  index: number; // Índice del elemento en el grupo
  total: number; // Total de elementos en el grupo
  fps: number; // Fotogramas por segundo
  width: number; // Ancho del lienzo
  height: number; // Alto del lienzo
  value: any; // Valor actual de la propiedad
}

Ejemplo de Expresión

Animación de rebote usando funciones de Math:

expressionAnimation.json
{
"id": "element-1",
"type": "Image",
"start": 0,
"duration": 5,
"animations": [
  {
    "type": "expression",
    "target": "y",
    "enabled": true,
    "expression": "100 + Math.abs(Math.sin(localTime * 3)) * 200",
    "startTime": 0,
    "duration": 5,
    "loop": true
  }
]
}

Expresión Compleja

Combina múltiples efectos:

complexExpression.json
{
"animations": [
  {
    "type": "expression",
    "target": "rotation",
    "expression": "(localTime * 2 * Math.PI / duration) + Math.sin(localTime * 4) * 0.1",
    "loop": true
  },
  {
    "type": "expression",
    "target": "scaleX",
    "expression": "1 + Math.sin(localTime * 5) * 0.2",
    "loop": true
  }
]
}

Animaciones Procedimentales

Patrones de animación incorporados con parámetros configurables.

Tipos Procedimentales

  • wiggle: Oscilación aleatoria (útil para efectos de cámara en mano)
  • wave: Movimiento de onda seno/coseno
  • bounce: Efecto de rebote elástico
  • pulse: Escalado rítmico

Ejemplo de Wiggle

wiggleAnimation.json
{
"animations": [
  {
    "type": "procedural",
    "proceduralType": "wiggle",
    "target": "rotation",
    "enabled": true,
    "frequency": 2,
    "amplitude": 0.1,
    "loop": true
  }
]
}

Animaciones de Secuencia

Animaciones basadas en pasos que cambian valores en intervalos específicos.

PropTipoRequeridoEjemploRango de ValoresDescripción
valuesarraytrue--Array de valores para recorrer.
stepDurationnumbertrue--Duración de cada paso en segundos.
loopbooleanfalse--Si se debe repetir la secuencia.

Ejemplo de Secuencia

Texto alternando entre diferentes tamaños:

sequenceAnimation.json
{
"animations": [
  {
    "type": "sequence",
    "target": "fontSize",
    "enabled": true,
    "values": [24, 32, 40, 32, 24],
    "stepDuration": 0.5,
    "loop": true
  }
]
}

Animaciones de Ruta

Anima elementos a lo largo de rutas de curva de Bezier.

PropTipoRequeridoEjemploRango de ValoresDescripción
pathstring | arraytrue--Datos de ruta SVG (atributo d) o array de puntos de ruta.
autoRotatebooleanfalse--Si se debe rotar automáticamente el elemento para seguir la tangente de la ruta.
durationnumbertrue--Tiempo para completar la ruta completa.

Ejemplo de Ruta

Movimiento circular:

pathAnimation.json
{
"animations": [
  {
    "type": "path",
    "target": "position",
    "enabled": true,
    "path": "M 100,100 a 200,200 0 1,1 0,1 Z",
    "autoRotate": true,
    "duration": 4,
    "loop": true
  }
]
}

Sintaxis de Ruta de Propiedad

La propiedad target utiliza notación de punto para especificar propiedades anidadas:

  • Simple: "x", "y", "rotation"
  • Anidada: "scale.x", "position.y"
  • Array: "colors[0]", "points[2].x"

Ejemplos de Resolución de Objetivos

{
  "target": "x"              // Posición x del elemento
  "target": "scaleX"         // Escala horizontal
  "target": "alpha"          // Opacidad
  "target": "fill.color"     // Color de relleno (si el relleno es un objeto)
  "target": "points[0].x"    // Coordenada x del primer punto
}

Modos de Mezcla

Controla cómo se combinan las animaciones cuando múltiples apuntan a la misma propiedad:

Reemplazar (Predeterminado)

{
  "blendMode": "replace",
  "blendWeight": 1.0
}

Reemplaza completamente el valor de la propiedad.

Sumar

{
  "blendMode": "add",
  "blendWeight": 0.5
}

Suma al valor existente (ponderado). Útil para acumular desplazamientos.

Multiplicar

{
  "blendMode": "multiply",
  "blendWeight": 1.0
}

Multiplica el valor existente. Útil para efectos de escalado.

Ejemplo de Múltiples Animaciones

Combinando diferentes tipos de animación:

multipleAnimations.json
{
"id": "animated-element",
"type": "Shape",
"animations": [
  {
    "type": "expression",
    "target": "x",
    "expression": "width / 2 + Math.sin(localTime * 2) * 300",
    "blendMode": "replace",
    "loop": true
  },
  {
    "type": "procedural",
    "proceduralType": "wiggle",
    "target": "rotation",
    "frequency": 3,
    "amplitude": 0.2,
    "blendMode": "add",
    "blendWeight": 0.5
  },
  {
    "type": "sequence",
    "target": "alpha",
    "values": [1, 0.8, 1],
    "stepDuration": 0.3,
    "loop": true,
    "blendMode": "multiply"
  }
],
"keyframes": [
  {
    "id": "kf-1",
    "time": 0,
    "stateObj": { "scaleX": 1 }
  },
  {
    "id": "kf-2",
    "time": 2,
    "stateObj": { "scaleX": 1.5 }
  }
]
}

En este ejemplo:

  • La expresión controla la posición horizontal (modo reemplazar)
  • El wiggle procedimental añade una variación sutil de rotación
  • La secuencia pulsa la opacidad
  • El fotograma clave escala el elemento (prioridad más baja)

Notas Importantes

Sandbox de Expresión

  • Las expresiones se ejecutan en un contexto restringido por razones de seguridad
  • Acceso solo a variables de contexto de animación
  • No se puede acceder al DOM, bibliotecas externas o API de Node.js
  • Errores de evaluación desactivarán la animación

Rendimiento

  • Expresiones: Evaluadas cada fotograma - mantenlas simples
  • Procedimental: Funciones incorporadas optimizadas - muy eficientes
  • Secuencia: Sobrecarga mínima, buena para cambios discretos
  • Ruta: Costo moderado, depende de la complejidad de la ruta

Temporización

  • startTime y duration son relativos al tiempo start del elemento
  • localTime en expresiones comienza en 0 cuando el elemento comienza
  • Las animaciones respetan el límite de duration general del elemento

Depuración

  • Si una animación no funciona, verifica:
    • enabled: true
    • La propiedad target existe en el elemento
    • La sintaxis de la expresión es JavaScript válida
    • startTime está dentro de la duración del elemento
    • No hay errores tipográficos en la ruta de la propiedad

Casos de Uso Comunes

Efecto de Seguimiento Suave

{
  "type": "expression",
  "target": "x",
  "expression": "value + (targetX - value) * 0.1"
}

Rebote Elástico

{
  "type": "expression",
  "target": "scaleY",
  "expression": "1 + Math.exp(-localTime * 3) * Math.cos(localTime * 8) * 0.5"
}

Sacudida de Cámara

{
  "type": "procedural",
  "proceduralType": "wiggle",
  "target": "x",
  "frequency": 10,
  "amplitude": 5
}

Animación Escalonada (en grupos)

{
  "type": "expression",
  "target": "alpha",
  "expression": "Math.max(0, Math.min(1, (localTime - index * 0.1) * 2))"
}