# Animationen, Keyframes und Übergänge

## 1. Planungsmodell

Lebenszyklus eines Clips auf oberster Ebene:
1. Warten bis `start`
2. Das Node in die Szene einfügen
3. Animationen, Keyframes und Übergänge während des aktiven Clip-Fensters ausführen
4. Den Lebenszyklus des Clips beenden

Paralleles Verhalten:
- `animations` und `keyframes` können parallel laufen
- Sichtbare `transition` kann bei Nicht-`audio`-Clips ebenfalls parallel laufen
- `audio`-Clips führen Audio-Automation statt visueller Übergänge aus

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

Derzeit unterstützte Animationstypen:
- `fadeIn`
- `fadeOut`
- `move`
- `scale`
- `rotate`
- `slideIn`
- `slideOut`
- `zoomIn`
- `zoomOut`

## 3. Verhalten der Felder

### `duration`
- Einheit: Sekunden
- Erforderlich
- Wenn `loop` aktiviert ist, verwendet ein Zyklus weiterhin diesen Wert als Basisdauer

### `delay`
- Einheit: Sekunden
- Optional
- Animationen mit derselben Verzögerung starten zusammen
- Animationen mit unterschiedlicher Verzögerung laufen zu ihrer jeweils geplanten Zeit

### `easing`
- Optional
- Standard ist `linear`, wenn der Wert weggelassen wird

### `loop`
- Typ: `boolean | number`
- `true`: so oft wie möglich innerhalb der verbleibenden Clip-Dauer wiederholen
- Zahl: für genau diese Anzahl an Zyklen wiederholen
- Wenn die gesamte Loop-Zeit das Clip-Fenster überschreitet, wird sie automatisch gekürzt

### `from`

Derzeit relevant für:
- `scale`
- `rotate`
- `move`

Hinweise:
- `move.from` sollte `{ x, y }` sein
- `scale.from` kann eine Zahl oder ein 2D-Wert sein
- `rotate.from` sollte eine Zahl sein

### `to`

Derzeit relevant für:
- `scale`
- `rotate`
- `move`

Hinweise:
- `move.to` sollte `{ x, y }` sein

### `direction`

Derzeit verwendet von:
- `slideIn`
- `slideOut`

Einige eingebaute Templates übergeben `direction` ebenfalls an ihre erzeugten Animationen.

### `distance`

Derzeit verwendet von:
- `slideIn`
- `slideOut`

Standard:
- In der Regel `200`, wenn der Wert fehlt

## 4. Verhalten nach Animationstyp

### `fadeIn`
- Startet mit Deckkraft `0`
- Animiert zur ursprünglichen Deckkraft

### `fadeOut`
- Animiert von der aktuellen Deckkraft zu `0`

### `zoomIn`
- Startet mit Skala `[0, 0]`
- Animiert zur ursprünglichen Skala

### `zoomOut`
- Animiert von der aktuellen Skala zu `[0, 0]`

### `slideIn`
- Startet mit einem Offset durch `direction + distance`
- Blendet zusätzlich von Deckkraft `0` ein

### `slideOut`
- Endet mit einer Auswärtsbewegung durch `direction + distance`
- Blendet zusätzlich auf Deckkraft `0` aus

### `scale`
- Wenn `from` vorhanden ist, wird die Skala zuerst auf `from` gesetzt
- Danach wird zu `to` animiert
- Fehlt `to`, kehrt sie zur ursprünglichen Skala zurück

### `rotate`
- Wenn `from` vorhanden ist, wird die Rotation zuerst gesetzt
- Danach wird zu `to` animiert
- Fehlt `to`, rotiert sie typischerweise bis `360`

### `move`
- `from` und `to` sollten beide Objekte sein
- Beispiel:

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

Aktuell bestätigte unterstützte Eigenschaften:
- `x`
- `y`
- `position`
- `opacity`
- `scale`
- `rotation`
- `width`
- `height`
- `fill`
- `stroke`

Verhalten:
- `frames` werden nach `time` sortiert
- Der erste Frame setzt den Anfangswert direkt
- Spätere Frames interpolieren zwischen den Zeitpunkten
- Nach dem letzten Keyframe wartet der Clip bis zu seinem eigenen Ende

## 6. `Transition`

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

Derzeit unterstützt:
- `fade`
- `slide`
- `zoom`
- `wipe`

Laufzeitverhalten:
- Jeder Übergang hat eine Intro-Phase und eine Outro-Phase
- Beide Phasen verwenden `transition.duration`
- Wenn die kombinierte Übergangszeit die Clip-Dauer überschreitet, kürzt die Laufzeit sie automatisch

## 7. Verhalten nach Übergangstyp

### `fade`
- Intro: Deckkraft `0 -> ursprüngliche Deckkraft`
- Outro: ursprüngliche Deckkraft `-> 0`

### `slide`
- Intro: von außerhalb der Zeichenfläche hineinschieben
- Outro: in die gewählte Richtung hinausschieben
- Deckkraft ändert sich gleichzeitig

### `zoom`
- Intro: hineinzoomen und einblenden
- Outro: herauszoomen und ausblenden

### `wipe`
- Ungefähr über Achsenskalierung umgesetzt
- Richtungen links und rechts komprimieren die horizontale Achse
- Richtungen oben und unten komprimieren die vertikale Achse

## 8. Liste der Easing-Funktionen

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

## 9. Steuerung des Audio-Timings

Zusätzlich zu normalen `start` und `duration` unterstützen `audio`-Clips auch:
- `source.start`
- `source.end`
- `fadeIn`
- `fadeOut`

Zusammen steuern diese:
- wann die Wiedergabe startet
- welcher Abschnitt der Quellmedien verwendet wird
- wie sich die Lautstärke im Zeitverlauf verändert

## 10. Beispiel: Titel-Intro, Halten und Ausstieg

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