# Animaciones, keyframes y transiciones

## 1. Modelo de programación

Ciclo de vida de un clip de nivel superior:
1. Esperar hasta `start`
2. Insertar el nodo en la escena
3. Ejecutar animaciones, keyframes y transiciones durante la ventana activa del clip
4. Finalizar el ciclo de vida del clip

Comportamiento en paralelo:
- `animations` y `keyframes` pueden ejecutarse en paralelo
- La `transition` visual también puede ejecutarse en paralelo para clips que no sean `audio`
- Los clips `audio` ejecutan automatización de audio en lugar de transiciones visuales

## 2. `Animation`

```ts
interface Animation {
  type: AnimationType;
  duration: number;
  delay?: number;
  easing?: EasingFunction;
  loop?: boolean | number;
  from?: any;
  to?: any;
  direction?: "left" | "right" | "up" | "down";
  distance?: number;
}
```

Tipos de animación compatibles actualmente:
- `fadeIn`
- `fadeOut`
- `move`
- `scale`
- `rotate`
- `slideIn`
- `slideOut`
- `zoomIn`
- `zoomOut`

## 3. Comportamiento de los campos

### `duration`
- Unidad: segundos
- Obligatorio
- Si `loop` está activado, un ciclo de bucle sigue usando este valor como duración base

### `delay`
- Unidad: segundos
- Opcional
- Las animaciones con el mismo retraso comienzan juntas
- Las animaciones con retrasos distintos se ejecutan en su propio momento programado

### `easing`
- Opcional
- Por defecto es `linear` cuando se omite

### `loop`
- Tipo: `boolean | number`
- `true`: repetir tantas veces como sea posible dentro de la duración restante del clip
- Número: repetir ese número de ciclos
- Si el tiempo total de bucle supera la ventana del clip, se recorta automáticamente

### `from`

Actualmente relevante para:
- `scale`
- `rotate`
- `move`

Notas:
- `move.from` debe ser `{ x, y }`
- `scale.from` puede ser un número o un valor 2D
- `rotate.from` debe ser un número

### `to`

Actualmente relevante para:
- `scale`
- `rotate`
- `move`

Notas:
- `move.to` debe ser `{ x, y }`

### `direction`

Actualmente usada por:
- `slideIn`
- `slideOut`

Algunas plantillas integradas también pasan `direction` a sus animaciones generadas.

### `distance`

Actualmente usada por:
- `slideIn`
- `slideOut`

Valor por defecto:
- Normalmente `200` cuando se omite

## 4. Comportamiento por tipo de animación

### `fadeIn`
- Comienza con opacidad `0`
- Anima hasta la opacidad original

### `fadeOut`
- Anima desde la opacidad actual hasta `0`

### `zoomIn`
- Comienza con escala `[0, 0]`
- Anima hasta la escala original

### `zoomOut`
- Anima desde la escala actual hasta `[0, 0]`

### `slideIn`
- Comienza desplazado por `direction + distance`
- También hace fade in desde opacidad `0`

### `slideOut`
- Termina moviéndose hacia fuera usando `direction + distance`
- También hace fade out hasta opacidad `0`

### `scale`
- Si existe `from`, la escala se fija primero en `from`
- Después anima hacia `to`
- Si falta `to`, vuelve a la escala original

### `rotate`
- Si existe `from`, primero se fija la rotación
- Después anima hacia `to`
- Si falta `to`, normalmente gira hasta `360`

### `move`
- `from` y `to` deben ser ambos objetos
- Ejemplo:

```json
{
  "type": "move",
  "duration": 1,
  "from": { "x": -200, "y": 0 },
  "to": { "x": 0, "y": 0 }
}
```

## 5. `keyframes`

```ts
interface Keyframe {
  property: string;
  frames: KeyframeFrame[];
}

interface KeyframeFrame {
  time: number;
  value: any;
  easing?: EasingFunction;
}
```

Propiedades actualmente confirmadas como compatibles:
- `x`
- `y`
- `position`
- `opacity`
- `scale`
- `rotation`
- `width`
- `height`
- `fill`
- `stroke`

Comportamiento:
- `frames` se ordenan por `time`
- El primer frame fija directamente el valor inicial
- Los frames posteriores interpolan entre puntos de control
- Después del último keyframe, el clip espera hasta su propio final

## 6. `Transition`

```ts
interface Transition {
  type: "fade" | "slide" | "zoom" | "wipe";
  duration: number;
  direction?: "left" | "right" | "up" | "down";
  easing?: EasingFunction;
}
```

Compatibles actualmente:
- `fade`
- `slide`
- `zoom`
- `wipe`

Comportamiento en runtime:
- Cada transición tiene una fase de entrada y una de salida
- Ambas fases usan `transition.duration`
- Si el tiempo combinado de transición supera la duración del clip, el runtime lo recorta automáticamente

## 7. Comportamiento por tipo de transición

### `fade`
- Entrada: opacidad `0 -> opacidad original`
- Salida: opacidad original `-> 0`

### `slide`
- Entrada: desliza desde fuera del canvas
- Salida: desliza hacia la dirección seleccionada
- La opacidad cambia al mismo tiempo

### `zoom`
- Entrada: hace zoom in y fade in
- Salida: hace zoom out y fade out

### `wipe`
- Implementada de forma aproximada mediante escalado de ejes
- Las direcciones izquierda y derecha comprimen el eje horizontal
- Las direcciones arriba y abajo comprimen el eje vertical

## 8. Lista de easing

Compatibles actualmente:
- `linear`
- `easeInSine`
- `easeOutSine`
- `easeInOutSine`
- `easeInQuad`
- `easeOutQuad`
- `easeInOutQuad`
- `easeInCubic`
- `easeOutCubic`
- `easeInOutCubic`
- `easeInQuart`
- `easeOutQuart`
- `easeInOutQuart`
- `easeInBack`
- `easeOutBack`
- `easeInOutBack`
- `easeInElastic`
- `easeOutElastic`
- `easeInOutElastic`
- `easeInBounce`
- `easeOutBounce`
- `easeInOutBounce`

## 9. Control de tiempo de audio

Además de `start` y `duration`, los clips `audio` también admiten:
- `source.start`
- `source.end`
- `fadeIn`
- `fadeOut`

Juntos controlan:
- cuándo comienza la reproducción
- qué segmento del medio de origen se utiliza
- cómo cambia el volumen con el tiempo

## 10. Ejemplo: entrada, permanencia y salida de un título

```json
{
  "type": "text",
  "start": 0,
  "duration": 4,
  "text": "Hello",
  "transform": {
    "x": "50%",
    "y": "50%"
  },
  "style": {
    "fontSize": 72,
    "fill": "#ffffff"
  },
  "animations": [
    {
      "type": "slideIn",
      "direction": "up",
      "distance": 120,
      "duration": 0.6,
      "easing": "easeOutCubic"
    },
    {
      "type": "fadeOut",
      "delay": 3.2,
      "duration": 0.6,
      "easing": "easeInSine"
    }
  ],
  "transition": {
    "type": "fade",
    "duration": 0.25
  }
}
```