# Animation, Keyframes, and Transitions

## 1. Scheduling model

Lifecycle of a top-level clip:
1. Wait until `start`
2. Insert the node into the scene
3. Run animations, keyframes, and transitions during the active clip window
4. End the clip lifecycle

Parallel behavior:
- `animations` and `keyframes` can run in parallel
- Visual `transition` can also run in parallel for non-`audio` clips
- `audio` clips run audio automation instead of visual transitions

## 2. `Animation`

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

Currently supported animation types:
- `fadeIn`
- `fadeOut`
- `move`
- `scale`
- `rotate`
- `filter`
- `slideIn`
- `slideOut`
- `zoomIn`
- `zoomOut`

## 3. Field behavior

### `duration`
- Unit: seconds
- Required
- If `loop` is enabled, one loop cycle still uses this value as the base duration

### `delay`
- Unit: seconds
- Optional
- Animations with the same delay start together
- Animations with different delays run at their own scheduled time

### `easing`
- Optional
- Defaults to `linear` when omitted

### `loop`
- Type: `boolean | number`
- `true`: repeat as many times as possible inside the remaining clip duration
- Number: repeat for that many cycles
- If total loop time exceeds the clip window, it is truncated automatically

### `from`

Currently meaningful for:
- `scale`
- `rotate`
- `move`
- `filter`

Notes:
- `move.from` should be `{ x, y }`
- `scale.from` can be a number or a 2D value
- `rotate.from` should be a number
- `filter.from` should be a number

### `to`

Currently meaningful for:
- `scale`
- `rotate`
- `move`
- `filter`

Notes:
- `move.to` should be `{ x, y }`
- `filter.to` should be a number

### `direction`

Currently used by:
- `slideIn`
- `slideOut`

Some built-in templates also pass `direction` into their generated animations.

### `distance`

Currently used by:
- `slideIn`
- `slideOut`

Default:
- Usually `200` when omitted

## 4. Behavior by animation type

### `fadeIn`
- Starts from opacity `0`
- Animates to the original opacity

### `fadeOut`
- Animates from the current opacity to `0`

### `zoomIn`
- Starts from `[0, 0]` scale
- Animates to the original scale

### `zoomOut`
- Animates from the current scale to `[0, 0]`

### `slideIn`
- Starts offset by `direction + distance`
- Also fades in from opacity `0`

### `slideOut`
- Ends by moving out using `direction + distance`
- Also fades out to opacity `0`

### `scale`
- If `from` exists, scale is set to `from` first
- Then it animates to `to`
- If `to` is missing, it returns to the original scale

### `rotate`
- If `from` exists, rotation is set first
- Then it animates to `to`
- If `to` is missing, it typically rotates to `360`

### `filter`
- The `filter` field selects one supported filter name
- Supported filters are `blur`, `brightness`, `contrast`, `saturate`, `hue`, `grayscale`, `sepia`, and `invert`
- The runtime animates the corresponding Revideo filter signal

```json
{
  "type": "filter",
  "filter": "blur",
  "duration": 0.8,
  "from": 0,
  "to": 24,
  "easing": "easeOutCubic"
}
```

### `move`
- `from` and `to` should both be objects
- Example:

```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;
}
```

Currently confirmed supported properties:
- `x`
- `y`
- `position`
- `opacity`
- `scale`
- `rotation`
- `width`
- `height`
- `fill`
- `stroke`
- `filters.blur`
- `filters.brightness`
- `filters.contrast`
- `filters.saturate`
- `filters.hue`
- `filters.grayscale`
- `filters.sepia`
- `filters.invert`
- `start`
- `end`
- `drawStart`
- `drawEnd`

Behavior:
- `frames` are sorted by `time`
- The first frame sets the initial value directly
- Later frames interpolate between checkpoints
- After the last keyframe, the clip waits until its own end

## 6. `Transition`

```ts
interface Transition {
  type:
    | "fade"
    | "slide"
    | "zoom"
    | "wipe"
    | "blur"
    | "push"
    | "iris"
    | "spin"
    | "lightSweep";
  duration: number;
  direction?: "left" | "right" | "up" | "down";
  easing?: EasingFunction;
  blur?: number;
  intensity?: number;
  rotation?: number;
  scale?: number;
}
```

Currently supported:
- `fade`
- `slide`
- `zoom`
- `wipe`
- `blur`
- `push`
- `iris`
- `spin`
- `lightSweep`

Runtime behavior:
- Each transition has an intro phase and an outro phase
- Both phases use `transition.duration`
- If combined transition time exceeds the clip duration, the runtime truncates it automatically

## 7. Behavior by transition type

### `fade`
- Intro: opacity `0 -> original opacity`
- Outro: original opacity `-> 0`

### `slide`
- Intro: slide in from outside the canvas
- Outro: slide out toward the selected direction
- Opacity changes at the same time

### `zoom`
- Intro: scale in and fade in
- Outro: scale out and fade out

### `wipe`
- Implemented approximately through axis scaling
- Left and right directions compress the horizontal axis
- Up and down directions compress the vertical axis

### `blur`
- Blends opacity with blur during intro and outro

### `push`
- Moves the clip through the selected direction for a stronger slide effect

### `iris`
- Reveals and hides through a radial scale mask style

### `spin`
- Adds rotation during transition

### `lightSweep`
- Applies a brightness sweep effect during transition

## 8. Easing list

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

## 9. Audio timing control

In addition to normal `start` and `duration`, `audio` clips also support:
- `source.start`
- `source.end`
- `fadeIn`
- `fadeOut`
- `pan`
- `detune`
- `gainEnvelope`

Together these control:
- when playback starts
- which segment of the source media is used
- how volume changes over time
- playback speed, stereo position, and detailed gain automation

## 10. Example: title intro, hold, and exit

```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
  }
}
```