# JSON-Struktur und Feldregeln

## 1. Struktur auf oberster Ebene

Die vollständige JSON-Form auf oberster Ebene lautet:

```json
{
  "meta": {},
  "assets": {},
  "tracks": []
}
```

Regeln:
- `meta` ist erforderlich
- `tracks` ist erforderlich und muss mindestens einen Track enthalten
- `assets` ist optional

Nicht unterstützt:
- Veraltetes Top-Level-`video`
- Veraltetes Top-Level-`audio`

## 2. `meta`

```ts
interface Meta {
  version: string;
  title?: string;
  description?: string;
  author?: string;
  createdAt?: string;
  tags?: string[];
  width: number;
  height: number;
  fps: number;
  background?: string | "transparent" | Gradient;
}
```

### `version`
- Typ: `string`
- Erforderlich: ja
- Zweck: Marker für die Schema-Version
- Empfohlener Wert: `"2.0.0"`

### `title`
- Typ: `string`
- Erforderlich: nein
- Zweck: Metadaten für den Videotitel

### `description`
- Typ: `string`
- Erforderlich: nein
- Zweck: Metadaten für die Videobeschreibung

### `author`
- Typ: `string`
- Erforderlich: nein
- Zweck: Autoren-Metadaten

### `createdAt`
- Typ: `string`
- Erforderlich: nein
- Zweck: Metadaten zur Erstellungszeit

### `tags`
- Typ: `string[]`
- Erforderlich: nein
- Zweck: Tagging-Metadaten

### `width`
- Typ: `number`
- Erforderlich: ja
- Einschränkung: positive Ganzzahl
- Zweck: Breite der Zeichenfläche

### `height`
- Typ: `number`
- Erforderlich: ja
- Einschränkung: positive Ganzzahl
- Zweck: Höhe der Zeichenfläche

### `fps`
- Typ: `number`
- Erforderlich: ja
- Einschränkung: positive Ganzzahl
- Zweck: Bildrate

### `background`
- Typ: `string | "transparent" | Gradient`
- Erforderlich: nein
- Standardwert: `"#000000"`
- Zweck: globaler Hintergrund

Form von Gradient:

```ts
interface Gradient {
  type: "linear" | "radial" | "conic";
  angle?: number;
  stops: Array<{
    offset: number;
    color: string;
  }>;
}
```

## 3. `assets`

```ts
interface Assets {
  fonts?: FontAsset[];
  images?: ImageAsset[];
  videos?: VideoAsset[];
  audios?: AudioAsset[];
  subtitles?: SubtitleAsset[];
}
```

### `fonts`

```ts
interface FontAsset {
  id: string;
  src: string;
  family: string;
}
```

Aktueller Laufzeitstatus:
- Es kann im JSON erscheinen
- Die Laufzeit lädt oder registriert Schriftarten nicht automatisch
- Behandle es nicht als vollständiges System zum Laden von Schriftarten

### `images`

```ts
interface ImageAsset {
  id: string;
  src: string;
}
```

### `videos`

```ts
interface VideoAsset {
  id: string;
  src: string;
}
```

### `audios`

```ts
interface AudioAsset {
  id: string;
  src: string;
}
```

### `subtitles`

```ts
interface SubtitleAsset {
  id: string;
  words: SubtitleWord[];
}
```

### Verwendung von `$ref`

Ressourcen-Pools mit Unterstützung für `$ref`:
- `images`
- `videos`
- `audios`
- `subtitles`

Beispiel:

```json
{
  "src": { "$ref": "video-hero" }
}
```

Oder:

```json
{
  "words": { "$ref": "subtitle-main" }
}
```

## 4. `tracks`

```ts
interface Track {
  id?: string;
  clips: Clip[];
}
```

### `id`
- Typ: `string`
- Erforderlich: nein
- Zweck: Track-Kennung

### `clips`
- Typ: `Clip[]`
- Erforderlich: ja
- Einschränkung: mindestens ein Clip

## 5. Gemeinsame `Clip`-Form

```ts
interface BaseClip {
  id?: string;
  type: ClipType;
  start: number;
  duration: number;
  transform?: Transform;
  zIndex?: number;
  opacity?: number;
  style?: Style;
  animations?: Animation[];
  keyframes?: Keyframe[];
  transition?: Transition;
}
```

Gemeinsame Kernfelder:

### `id`
- Typ: `string`
- Erforderlich: nein
- Zweck: Clip-Kennung

### `type`
- Typ: `ClipType`
- Erforderlich: ja

Derzeit unterstützt:
- `video`
- `image`
- `text`
- `rect`
- `circle`
- `polygon`
- `audio`
- `subtitle`
- `layout`
- `template`

### `start`
- Typ: `number`
- Erforderlich: ja
- Einheit: Sekunden
- Zweck: Startzeit des Clips

### `duration`
- Typ: `number`
- Erforderlich: ja
- Einheit: Sekunden
- Zweck: Dauer des Clips

### `transform`
- Typ: `Transform`
- Erforderlich: nein

### `zIndex`
- Typ: `number`
- Erforderlich: nein
- Standardwert: `0`

### `opacity`
- Typ: `number`
- Erforderlich: nein
- Standardwert: `1`
- Zweck: Kurzform für die Deckkraft sichtbarer Elemente
- Kompatibilitätsregel: `style.opacity` hat höhere Priorität als das Top-Level-`opacity`

### `style`
- Typ: `Style`
- Erforderlich: nein

### `animations`
- Typ: `Animation[]`
- Erforderlich: nein

### `keyframes`
- Typ: `Keyframe[]`
- Erforderlich: nein

### `transition`
- Typ: `Transition`
- Erforderlich: nein

## 6. Regeln für Koordinaten und Prozentwerte

Prozentuale Koordinaten basieren auf dem zentrierten Koordinatensystem von Revideo, nicht auf einem DOM-Ursprung oben links.

Beispiele:
- `x: "50%"` bedeutet horizontal zentriert
- `y: "50%"` bedeutet vertikal zentriert
- `x: "0%"` bedeutet ganz links
- `x: "100%"` bedeutet ganz rechts
- `y: "0%"` bedeutet oben
- `y: "100%"` bedeutet unten

## 7. Minimales gültiges JSON

```json
{
  "meta": {
    "version": "2.0.0",
    "width": 1920,
    "height": 1080,
    "fps": 30,
    "background": "#000000"
  },
  "tracks": [
    {
      "clips": [
        {
          "type": "text",
          "start": 0,
          "duration": 3,
          "text": "Hello, world",
          "transform": {
            "x": "50%",
            "y": "50%"
          },
          "style": {
            "fontSize": 72,
            "fill": "#ffffff",
            "textAlign": "center"
          }
        }
      ]
    }
  ]
}
```

## 8. Hinweis für öffentliche Integrationen

Für externe Integrationen verwende den in [API und Verwendung](https://renderingvideo.com/docs/api-and-usage.md) dokumentierten Ablauf:
- Reiche dein Schema über `POST /api/preview` ein
- Sende das vollständige Schema-JSON als Request-Body
- Fehlende Top-Level-Felder `meta` oder `tracks` müssen weiterhin als ungültige Eingabe behandelt werden
- Ein falscher Feldname innerhalb eines Clips führt nicht immer schon zum Fehler beim Request
- Manche Fehler werden erst bei Vorschau, Wiedergabe oder Rendern sichtbar