diff --git a/.gitignore b/.gitignore
index 920df8e17..1fd4fdcf0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,6 @@
/build*/
build
# Doxygen
-/docs/
# Visual Studio (Code)
.localhistory/
diff --git a/docs/project-file-reference-zh.md b/docs/project-file-reference-zh.md
new file mode 100644
index 000000000..95f7ea515
--- /dev/null
+++ b/docs/project-file-reference-zh.md
@@ -0,0 +1,306 @@
+# Olive 项目文件参考手册(详细版)
+
+本文档基于当前源代码实现,描述 Olive 的 XML 项目文件格式,目标是足够详细以实现兼容读写器。
+
+> 代码来源:`app/node/project.cpp`、`app/node/node.cpp`、`app/node/value.*`、`app/node/keyframe.*`、`app/node/project/serializer/*`。
+
+## 1. 根元素
+
+```xml
+
+ ...
+
+```
+
+- `version`:序列化版本号(`YYMMDD`)。
+- `url`:可选的项目文件路径。
+
+## 2. 项目容器
+
+完整保存时,会有 `project` 容器:
+
+```xml
+
+ ...
+ ...
+
+```
+
+- 内层 ``:项目数据。
+- ``:界面布局(`MainWindowLayoutInfo::fromXml`)。
+
+## 3. 项目数据(`Project::Save`)
+
+```xml
+
+ ...
+ ...
+ ...
+ ...
+
+```
+
+### 3.1 `uuid`
+项目 UUID(QUuid 字符串)。
+
+### 3.2 `plugins`
+项目中使用的 OpenFX 插件列表,用于加载节点前补充插件搜索路径。
+
+```xml
+
+
+
+```
+
+属性:
+- `id`:OFX 插件标识符(与节点 `id` 相同)。
+- `major` / `minor`:插件版本。
+- `bundle`:插件 bundle 目录路径(优先使用)。
+- `file`:插件二进制路径(备用)。
+
+加载策略:
+- 若存在 ``,先把 `bundle`(或 `file`)加入 OFX 搜索路径并扫描,然后注册插件节点,再进入 `` 解析。
+
+### 3.3 `nodes`
+节点图,节点由 `Node::Save()` 写出:
+
+```xml
+
+
+
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+
+
+```
+
+关键属性:
+- `id`:节点类型标识。OpenFX 节点为插件标识符。
+- `ptr`:序列化指针 ID,用于恢复连接与位置。
+- `version`:当前为 `1`。
+
+### 3.4 `settings`
+项目设置,键值对形式保存:
+
+已知键:
+- `cachesetting`
+- `customcachepath`
+- `colorconfigfilename`
+- `defaultinputcolorspace`
+- `colorreferencespace`
+- `root`
+
+## 4. 节点序列化(`Node::Save` / `Node::Load`)
+
+### 4.1 `label`
+节点显示名。
+
+### 4.2 `color`
+节点覆盖颜色(整数索引)。
+
+### 4.3 `input`
+每个输入:
+
+```xml
+
+ ...
+
+ ...
+
+
+```
+
+- `primary`:主元素(element = -1)。
+- `subelements`:数组输入,`count` 为数组长度。
+
+#### 4.3.1 立即值结构(`primary` / `element`)
+
+```xml
+0|1
+
+
+
+
+
+
+...
+...
+...
+...
+```
+
+- `keyframing`:是否启用关键帧(仅在输入可关键帧时写出)。
+- `standard`:默认值(每条 track 一份)。
+- `keyframes`:仅当 `keyframing=1` 时写出。
+- `cs*`:仅用于 `kColor`,保存色彩管理信息。
+
+#### 4.3.2 Track 数量
+由 `NodeValue::get_number_of_keyframe_tracks()` 决定:
+
+| 类型 | Track 数量 |
+| --- | --- |
+| kVec2 | 2 |
+| kVec3 | 3 |
+| kVec4 | 4 |
+| kColor | 4 |
+| kBezier | 6 |
+| 其他 | 1 |
+
+#### 4.3.3 标准值编码
+由 `NodeValue::ValueToString()` 写出,`NodeValue::StringToValue()` 读入:
+
+- `kVec2`: `x:y`
+- `kVec3`: `x:y:z`
+- `kVec4`: `x:y:z:w`
+- `kColor`: `r:g:b:a`
+- `kBezier`: `x:y:cp1x:cp1y:cp2x:cp2y`
+- `kRational`: `num/den`
+- `kInt`: 整数文本
+- `kBinary`: Base64
+- `kText` / `kFont` / `kFile` / `kCombo` / `kStrCombo`: 纯文本
+- `kTexture` / `kSamples` / `kNone`: 无文本
+
+特殊情况:
+- `kVideoParams` / `kAudioParams` 以子对象形式保存(见第 5/6 节)。
+- `kSubtitleParams` 在加载时被跳过(避免覆盖实际字幕数据)。
+
+#### 4.3.4 关键帧(`NodeKeyframe::save`)
+
+```xml
+value
+```
+
+- `input`:输入 ID。
+- `time`:理性时间。
+- `type`:关键帧类型枚举值。
+- `inhandlex` / `inhandley` / `outhandlex` / `outhandley`:贝塞尔控制点。
+
+文本值使用 `NodeValue::ValueToString(data_type, value, true)`。
+
+### 4.4 `links`
+节点间的“块”链接:
+
+```xml
+
+ ptr
+
+```
+
+### 4.5 `connections`
+输入/输出连接:
+
+```xml
+
+
+
+
+
+```
+
+### 4.6 `hints`(输入提示)
+
+```xml
+
+
+
+ ...
+
+ 0
+ ...
+
+
+```
+
+### 4.7 `context`(节点位置)
+
+```xml
+
+
+ 0
+ 0
+ 0|1
+
+
+```
+
+### 4.8 `caches`
+
+```xml
+
+
+
+ uuid
+ uuid
+
+```
+
+### 4.9 `custom`
+节点自定义内容,默认实现为空;各子类可覆盖。
+
+## 5. VideoParams
+`kVideoParams` 输入以子对象保存:
+
+```xml
+...
+...
+...
+num/den
+int
+int
+num/den
+int
+int
+0|1
+float
+float
+int
+int
+num/den
+int64
+int64
+0|1
+string
+int
+```
+
+## 6. AudioParams
+`kAudioParams` 输入以子对象保存:
+
+```xml
+int
+uint64
+string
+0|1
+int
+int64
+num/den
+```
+
+## 7. 部分保存
+序列化器支持写出部分数据:
+
+- ``
+- ``
+- ``(子集)
+
+## 8. OpenFX 插件兼容
+
+- OpenFX 节点 `id` 等于插件标识符。
+- `` 记录插件路径,加载时会先扫描并注册插件节点。
+- 插件缺失时节点无法实例化并被跳过。
+
+## 9. 版本兼容
+
+- 根元素 `version` 决定使用哪个序列化器。
+- 若缺少对应版本,会报 `kProjectTooNew` 或 `kProjectTooOld`。
+
diff --git a/docs/project-file-reference.md b/docs/project-file-reference.md
new file mode 100644
index 000000000..cf3830dbc
--- /dev/null
+++ b/docs/project-file-reference.md
@@ -0,0 +1,317 @@
+# Olive Project File Reference
+
+This document describes Olive's XML project format as implemented in the current codebase. It is intended to be detailed enough to implement a compatible reader/writer.
+
+> Source of truth: `app/node/project.cpp`, `app/node/node.cpp`, `app/node/value.*`, `app/node/keyframe.*`, `app/node/project/serializer/*`.
+
+## 1. Root Document
+
+```xml
+
+ ...
+
+```
+
+- `version`: serializer version in `YYMMDD` format (latest is `230220`).
+- `url`: optional source path.
+
+## 2. Project Container
+
+For full saves, the serializer writes a project container:
+
+```xml
+
+ ...
+ ...
+
+```
+
+- Inner `` stores actual project data.
+- `` stores UI layout (`MainWindowLayoutInfo::fromXml`).
+
+## 3. Project Data (`Project::Save`)
+
+```xml
+
+ ...
+ ...
+ ...
+ ...
+
+```
+
+### 3.1 `uuid`
+- QUuid string.
+
+### 3.2 `plugins`
+List of OpenFX plugins referenced by nodes in the project. This is used during load to rescan plugin paths **before** nodes are instantiated.
+
+```xml
+
+
+
+```
+
+Attributes:
+- `id`: OFX plugin identifier (matches node `id`).
+- `major` / `minor`: OFX plugin version.
+- `bundle`: bundle directory path (preferred).
+- `file`: plugin binary path (fallback).
+
+Loading behavior:
+- If `plugins` exists, Olive adds each `bundle` (or `file` if `bundle` empty) to the OFX plugin path, scans, then registers plugin nodes before parsing ``.
+
+### 3.3 `nodes`
+The node graph. Each `` is written by `Node::Save()` and read by `Node::Load()`.
+
+```xml
+
+
+
+ 3
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+
+
+```
+
+Attributes:
+- `id`: node type identifier. For OpenFX nodes, this equals the OFX plugin identifier.
+- `ptr`: numeric pointer ID used to resolve connections and context positions.
+- `version`: currently `1`.
+
+### 3.4 `settings`
+Project settings stored as key/value text elements.
+
+Known keys from code:
+- `cachesetting`
+- `customcachepath`
+- `colorconfigfilename`
+- `defaultinputcolorspace`
+- `colorreferencespace`
+- `root` (pointer id of the root Folder node)
+
+## 4. Node Serialization (`Node::Save` / `Node::Load`)
+
+### 4.1 `label`
+User-visible node label.
+
+### 4.2 `color`
+Override color index (integer), only written if not `-1`.
+
+### 4.3 `input`
+Each input is serialized as:
+
+```xml
+
+ ...
+
+ ...
+
+
+```
+
+- `primary`: element `-1` (the main input).
+- `subelements`: array elements (if input is an array). `count` is the array size.
+
+#### 4.3.1 Immediate Values (`primary` / `element`)
+Each immediate block contains:
+
+```xml
+0|1
+
+
+ ...
+
+
+
+
+...
+...
+...
+...
+```
+
+- `keyframing`: whether input is keyframed (only written if input is keyframable).
+- `standard`: default/static values (one `