# Structure JSON et règles des champs

## 1. Structure de premier niveau

La forme JSON complète au niveau supérieur est :

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

Règles :
- `meta` est requis
- `tracks` est requis et doit contenir au moins un track
- `assets` est optionnel

Non pris en charge :
- Ancien `video` au niveau supérieur
- Ancien `audio` au niveau supérieur

## 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`
- Type : `string`
- Requis : oui
- Rôle : marqueur de version du schéma
- Valeur recommandée : `"2.0.0"`

### `title`
- Type : `string`
- Requis : non
- Rôle : métadonnées du titre vidéo

### `description`
- Type : `string`
- Requis : non
- Rôle : métadonnées de description vidéo

### `author`
- Type : `string`
- Requis : non
- Rôle : métadonnées d'auteur

### `createdAt`
- Type : `string`
- Requis : non
- Rôle : métadonnées de date de création

### `tags`
- Type : `string[]`
- Requis : non
- Rôle : métadonnées de balisage

### `width`
- Type : `number`
- Requis : oui
- Contrainte : entier positif
- Rôle : largeur du canvas

### `height`
- Type : `number`
- Requis : oui
- Contrainte : entier positif
- Rôle : hauteur du canvas

### `fps`
- Type : `number`
- Requis : oui
- Contrainte : entier positif
- Rôle : fréquence d'images

### `background`
- Type : `string | "transparent" | Gradient`
- Requis : non
- Valeur par défaut : `"#000000"`
- Rôle : arrière-plan global

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

Statut actuel à l'exécution :
- Il peut apparaître dans le JSON
- Le runtime ne télécharge ni n'enregistre automatiquement les polices
- Ne le considérez pas comme un système complet de chargement des polices

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

### Utilisation de `$ref`

Pools de ressources qui prennent en charge `$ref` :
- `images`
- `videos`
- `audios`
- `subtitles`

Exemple :

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

Ou :

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

## 4. `tracks`

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

### `id`
- Type : `string`
- Requis : non
- Rôle : identifiant du track

### `clips`
- Type : `Clip[]`
- Requis : oui
- Contrainte : au moins un clip

## 5. Forme partagée de `Clip`

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

Champs de base partagés :

### `id`
- Type : `string`
- Requis : non
- Rôle : identifiant du clip

### `type`
- Type : `ClipType`
- Requis : oui

Actuellement pris en charge :
- `video`
- `image`
- `text`
- `rect`
- `circle`
- `polygon`
- `audio`
- `subtitle`
- `layout`
- `template`

### `start`
- Type : `number`
- Requis : oui
- Unité : secondes
- Rôle : heure de début du clip

### `duration`
- Type : `number`
- Requis : oui
- Unité : secondes
- Rôle : durée du clip

### `transform`
- Type : `Transform`
- Requis : non

### `zIndex`
- Type : `number`
- Requis : non
- Valeur par défaut : `0`

### `opacity`
- Type : `number`
- Requis : non
- Valeur par défaut : `1`
- Rôle : raccourci d'opacité pour les éléments visibles
- Règle de compatibilité : `style.opacity` a priorité sur `opacity` au niveau supérieur

### `style`
- Type : `Style`
- Requis : non

### `animations`
- Type : `Animation[]`
- Requis : non

### `keyframes`
- Type : `Keyframe[]`
- Requis : non

### `transition`
- Type : `Transition`
- Requis : non

## 6. Règles sur les coordonnées et les pourcentages

Les coordonnées en pourcentage sont basées sur le système de coordonnées centré de Revideo, et non sur une origine en haut à gauche comme dans le DOM.

Exemples :
- `x: "50%"` signifie centré horizontalement
- `y: "50%"` signifie centré verticalement
- `x: "0%"` signifie tout à gauche
- `x: "100%"` signifie tout à droite
- `y: "0%"` signifie en haut
- `y: "100%"` signifie en bas

## 7. JSON valide minimal

```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. Remarque pour les intégrations publiques

Pour les intégrations externes, utilisez le flux documenté dans [API et utilisation](https://renderingvideo.com/docs/api-and-usage.md) :
- Soumettez votre schéma via `POST /api/preview`
- Envoyez le JSON complet du schéma comme corps de requête
- L'absence de `meta` ou `tracks` au niveau supérieur doit toujours être traitée comme une entrée invalide
- Un mauvais nom de champ dans un clip ne provoque pas toujours une erreur dès la requête
- Certaines erreurs ne deviennent visibles qu'au moment de l'aperçu, de la lecture ou du rendu