# JSON 结构与字段规范

## 1. 顶层结构

完整 JSON 顶层：

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

说明：
- `meta` 必填
- `tracks` 必填，且至少包含 1 个 track
- `assets` 可选


## 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`
- 类型：`string`
- 必填：是
- 用途：标识 schema 版本
- 建议值：`"2.0.0"`

### `title`
- 类型：`string`
- 必填：否
- 用途：视频标题元数据

### `description`
- 类型：`string`
- 必填：否
- 用途：视频描述元数据

### `author`
- 类型：`string`
- 必填：否
- 用途：作者元数据

### `createdAt`
- 类型：`string`
- 必填：否
- 用途：创建时间元数据

### `tags`
- 类型：`string[]`
- 必填：否
- 用途：标签元数据

### `width`
- 类型：`number`
- 必填：是
- 限制：必须是正整数
- 用途：画布宽度

### `height`
- 类型：`number`
- 必填：是
- 限制：必须是正整数
- 用途：画布高度

### `fps`
- 类型：`number`
- 必填：是
- 限制：必须是正整数
- 用途：播放帧率

### `background`
- 类型：`string | "transparent" | Gradient`
- 必填：否
- 默认值：`"#000000"`
- 用途：全局背景

渐变对象：

```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[];
  models?: ModelAsset[];
  svgs?: SvgAsset[];
}
```

### `fonts`

```ts
interface FontAsset {
  id: string;
  src: string;
  family: string;
  weight?: number | string;
  style?: "normal" | "italic";
}
```

运行时会通过 `FontFace` 注册字体。文本元素或字幕里使用同名 `fontFamily` 即可引用。

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

### `models`

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

用于 `three` 元素里的 GLTF/GLB 模型引用。

### `svgs`

```ts
interface SvgAsset {
  id: string;
  svg?: string;
  src?: string;
}
```

`svg` 用于 inline SVG，`src` 用于远程 SVG 文件地址。

### `$ref` 用法

支持 `$ref` 的资源池：
- `images`
- `videos`
- `audios`
- `subtitles`
- `models`
- `svgs`

格式：

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

或：

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

## 4. `tracks`

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

字段说明：

### `id`
- 类型：`string`
- 必填：否
- 用途：track 标识

### `clips`
- 类型：`Clip[]`
- 必填：是
- 限制：至少 1 个

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

所有 clip 共有的核心字段：

### `id`
- 类型：`string`
- 必填：否
- 用途：标识 clip

### `type`
- 类型：`ClipType`
- 必填：是

当前支持：
- `video`
- `image`
- `text`
- `rect`
- `circle`
- `polygon`
- `code`
- `svg`
- `icon`
- `line`
- `path`
- `three`
- `audio`
- `subtitle`
- `layout`
- `template`

### `start`
- 类型：`number`
- 必填：是
- 单位：秒
- 用途：开始时间

### `duration`
- 类型：`number`
- 必填：是
- 单位：秒
- 用途：持续时间

### `transform`
- 类型：`Transform`
- 必填：否

### `zIndex`
- 类型：`number`
- 必填：否
- 默认值：`0`

### `opacity`
- 类型：`number`
- 必填：否
- 默认值：`1`
- 用途：所有可见元素的透明度快捷字段
- 兼容规则：`style.opacity` 优先级高于 `opacity`

### `style`
- 类型：`Style`
- 必填：否

### `animations`
- 类型：`Animation[]`
- 必填：否

### `keyframes`
- 类型：`Keyframe[]`
- 必填：否

### `transition`
- 类型：`Transition`
- 必填：否

## 6. 坐标与百分比规则

百分比并不是 DOM 那种左上角原点，而是基于 Revideo 中心坐标系。

换算规则：
- `x: "50%"` 表示水平居中
- `y: "50%"` 表示垂直居中
- `x: "0%"` 表示最左侧
- `x: "100%"` 表示最右侧
- `y: "0%"` 表示最上侧
- `y: "100%"` 表示最下侧

## 7. 顶层最小可用 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. 对外集成说明

对外集成时，使用 [API 与使用方式](https://renderingvideo.com/docs/api-and-usage.md) 中公开的流程：
- 通过 `POST /api/preview` 提交
- 将完整 schema JSON 直接作为请求体提交
- 顶层缺少 `meta` 或 `tracks` 仍然应当视为无效输入
- clip 内部字段名写错，不一定会在请求阶段立即报错
- 有些错误只会在预览、播放或渲染阶段暴露