# Nomi 结构化创作 + 项目目录 PRD

日期：2026-05-24
版本：v1 (草稿)
依赖文档：
- `nomi-product-prd-v2-2026-05-23.md` (战略定位 + 视觉设计层)
- `nomi-differentiation-prd-2026-05-23.md` (差异化分析)

> 本文档把"项目目录树 + 子画布"与"结构化剧本语法"合并成一个产品命题，因为它们必须同时存在才能产生 1+1=10 的化学反应。

---

## 0. 速读

**一句话**：

> 用户在创作区按结构化语法写剧本，画布**自动**沿着角色、场景、分镜等维度组织出可视化资产图谱，画布的左侧目录树是这个图谱的导航器。

**为什么这是 Nomi 的关键差异化**：

- Figma 不能这样做 — 它没有"角色复用 + 场景复用 + 剧本驱动"的领域模型
- Krea 不能这样做 — 它是单画布的实时生成器
- ComfyUI 不能这样做 — 它是节点工程师工具，不是创作工具
- Notion / Obsidian 能管理知识但不能与 AI 生成原语融合
- Final Draft 能管理剧本但不能生成视觉资产

**Nomi 是唯一能把"结构化写作 + 视觉资产 + AI 生成"在同一个本地项目里融合的产品**。这是 PRD v2 §4 三大支柱（项目记忆 + 生产图 + Agent runtime）真正落地的形态。

**核心心智**：

> 项目 = 一份带类型的剧本 + 它自动派生的资产图谱。资产不再是"生成后的副产物"，而是"剧本中实体的视觉化身"。

**三个阶段交付**：

| 阶段 | 主题 | 版本 |
|---|---|---|
| Phase E | 项目目录 + 默认 8 个分类 + 子画布切换 | v0.5 |
| Phase F | Nomi Script 结构化语法 + 双向绑定 | v0.6 |
| Phase G | 关系图谱 + 跨子画布资产引用 + AI Agent 集成 | v0.7 |

---

## 1. 战略定位

### 1.1 问题观察

**当前的 Nomi 创作过程**：
1. 创作区 TipTap 编辑器：用户写自由 markdown
2. 生成区：所有节点（角色、场景、图片、视频、分镜）扁平地堆在一张画布上
3. 时间轴：手动从画布拖入节点

**问题**：
- **角色一致性灾难**：用户在 12 个镜头里描述"小苏"，每次手写一遍，结果生成时角色变形
- **场景复用断裂**：第一幕和第三幕都在"咖啡馆"，但两次生成的图风格不一致
- **当资产 > 20 个时画布找不到东西**：扁平画布无法表达层级
- **剧本和资产没有绑定**：改剧本不影响画布；改画布不改剧本；同步靠人脑
- **AI Agent 缺乏结构化输入**：每次都要从一堆文字里推断角色/场景/镜头的关系

**核心症结**：剧本是非结构化文本，画布是非分类节点池，两者之间没有可机器读的桥梁。

### 1.2 我们的判断

> **创作不应该是"写文字 → 手动拆解 → 一个一个生成 → 手动组装"。**
> **创作应该是"写一份带类型的剧本 → 系统自动派生角色卡、场景卡、镜头节点 → AI 按结构化提示生成 → 时间轴自动接住"。**

把"结构化"和"分类"这两件事拆开做会做不通：
- 只做目录树没有结构化剧本 → 用户还是手动建分类、手动迁移节点，没有"自动派生"的杠杆
- 只做结构化剧本没有目录树 → 派生出的实体堆在一张画布上，仍然乱

**两件事必须捆绑设计、并行交付**。

### 1.3 与 v2 PRD 的关系

| v2 PRD §4 支柱 | 本 PRD 的落地形态 |
|---|---|
| 支柱 1: 本地项目仓库 | 项目目录是文件夹结构的可视化镜像；每个子分类有自己的资产子目录 |
| 支柱 2: 开源扩展生态 | Nomi Script 语法本身可被 skill 扩展；分类可被 Skill Pack 注册 |
| 支柱 3: Project Memory + Production Graph + Agent | **本 PRD 是这个支柱的核心落地**：剧本=Memory，分类+关系=Graph，结构化数据=Agent 的一等输入 |
| 支柱 4: 视觉设计层 | 子画布的"特殊画布行为"就是支柱 4 在领域语境下的具现化 |

### 1.4 反向定义：我们绝不做什么

| 不做 | 原因 |
|---|---|
| 完整的工业级剧本工具 | Final Draft / Celtx 已经做得很好，不是我们主场 |
| 复杂关系图谱 query 语言 | Notion / Roam 是知识工具，我们是创作工具 — 简单关系够用 |
| 多人实时编辑结构化文档 | 仍然单机优先 |
| 强制用户使用结构化语法 | 自由 markdown 永远可用，结构化是渐进的强化 |

---

## 2. 三类用户场景

### 场景 A：AI 漫剧创作者小苏

**目标**：做一集 5 分钟的二次元短剧，主角小苏，3 个配角，5 个场景，30 个镜头。

**当前痛点**：
- 30 个镜头每次都要把"小苏白衬衫长发"再写一遍
- 5 个场景每次描述差一点，生成的咖啡馆每次都不一样
- 改一句台词要手动找到对应的镜头节点，找不到

**Nomi 后**：
- 在创作区写一次 `@角色 小苏 { ... }`，整个项目里所有镜头都自动 reference 这张角色卡
- 写 `@场景 咖啡馆 { 风格参考: 北京三里屯下午 }`，所有"咖啡馆"镜头自动继承
- 改剧本里"@镜头 5 的动作"，画布上对应节点的 prompt 自动更新
- 角色子画布显示 4 张角色卡 + "每个被引用了 N 次" 徽标，一眼能看出主角谁戏多

### 场景 B：内容博主老王

**目标**：做一个 "用 Nomi 30 分钟做漫剧" 的教程视频。

**当前痛点**：
- 录屏时画布乱，观众看不清流程
- 想给观众一个"项目模板"让他们下载来跟做，但目前 .nomiproj 是不结构化的 JSON
- 想展示"剧本变成画布"的瞬间，但目前没有这个瞬间

**Nomi 后**：
- 录屏时左侧目录树清晰呈现"故事 → 角色 → 场景 → 分镜"工作流
- 一行 `@角色 张三` 写完，按 Tab，画布右上角浮现张三的卡片 — 这就是教程的高光时刻
- 模板项目可以发给观众，他们打开就看到结构化剧本框架

### 场景 C：独立工作室美术总监

**目标**：3 人团队做独立游戏概念美术，需要保密、长期演化、多人按角色/场景分工。

**当前痛点**：
- ComfyUI 太工程化，团队美术受不了
- Figma 没有"角色一致性"概念
- 项目跑半年后回头看，不知道当初为什么这么决定

**Nomi 后**：
- 团队成员甲专攻"角色"子画布，乙专攻"场景"子画布 — 各自专注
- 剧本里的 `@角色` 块自带 LoRA 配置和参考图，新成员入职打开剧本就能复刻整套美术语言
- `@决策日志` 块记录"我们为什么选黄昏色调"，半年后翻回来还能看到原因

---

## 3. 核心概念

### 3.1 项目目录树

项目左侧有一个垂直栏目，列出所有**分类（Category）**。每个分类是一个**子画布**。点击分类，主画布切换到对应的子画布视图。

```
+ 项目库 > 未命名漫剧 06_01
+-----------------+---------------------------------------+
| 📖 故事 (1)     |                                       |
| 👥 角色 (4)     |                                       |
| 🌍 场景 (5)     |     [当前子画布的内容]                |
| 🎨 风格 (1)     |                                       |
| 🎬 分镜 (30)    |                                       |
| 🎵 声音 (3)     |                                       |
| 🖼️ 资源池 (12)  |                                       |
| 📦 导出 (2)     |                                       |
| + 新分类        |                                       |
+-----------------+---------------------------------------+
| 时间轴...                                               |
+---------------------------------------------------------+
```

### 3.2 子画布的"领域感"

每个分类的画布不是泛用画布的换皮，而是为该领域优化：

| 分类 | 默认视图 | 专属能力 |
|---|---|---|
| 📖 故事 | 全屏 TipTap + 结构化语法高亮 | Slash command 插入 `@角色 / @场景 / @镜头`；改文本自动同步图谱 |
| 👥 角色 | 卡片网格 (4 列) | 每张卡含名称/描述/参考图/LoRA；右键"在哪些镜头里出现" |
| 🌍 场景 | 卡片网格 + 可选地图视图 | 场景含光线/氛围/风格参考；可绑定 panorama 节点 |
| 🎨 风格 | 单画布，配色卡 + 风格参考网格 | 颜色取色器；批量 "把这个风格应用到选中镜头" |
| 🎬 分镜 | 现有 generationCanvas 画布 | 按 edge 自动排序成时间轴；缩略图 + 镜号 + duration |
| 🎵 声音 | 列表 + 波形预览 | 拖到时间轴 audio track；按情绪/类型筛选 |
| 🖼️ 资源池 | 平铺网格 + 多维筛选 | 未分类的导入素材；右键"归类到 …" |
| 📦 导出 | 列表 + 状态徽标 | 历次导出版本，分辨率/格式/文件大小；一键分享 |

**关键设计**：分类不仅是文件夹，还是**带不同语言的子工作台**。

### 3.3 Nomi Script 结构化语法

在创作区（📖 故事）的 TipTap 编辑器里支持新的 **Block 语法**，类似 Notion 的 slash command + Fountain 的纯文本约定。

#### 3.3.1 语法形态

```nomi
# 第一幕：偶遇

@角色 小苏 {
  外观: 25 岁女生，及肩长发，白衬衫卡其裤
  性格: 内向但充满好奇心
  参考: img:soso-ref-001
  LoRA: anime-girl-v2  
}

@角色 老王 {
  外观: 35 岁男生，黑框眼镜，灰色西装
  性格: 老派但浪漫
  参考: img:laowang-ref-001
}

@场景 咖啡馆 {
  地点: 北京三里屯
  氛围: 安静，午后阳光，木质书架
  光线: 暖黄色 4500K
  参考: img:cafe-ref-001
  风格: 风格.京都漫画
}

@关系 {
  小苏 ↔ 老王: 大学同学，五年未见
  小苏 ⇒ 咖啡馆: 每周三下午常去
}

@镜头 1 {
  场景: 咖啡馆
  角色: [小苏]
  动作: 小苏推门进入，环顾四周
  景别: 中景
  duration: 3s
}

@镜头 2 {
  场景: 咖啡馆
  角色: [小苏, 老王]
  动作: 老王从书架后转身，目光相遇
  景别: 双人特写
  duration: 4s
}

@对白 小苏 → 老王: 好久不见。
@对白 老王 → 小苏: 嗯，五年了。

@决策 风格选择 {
  日期: 2026-05-24
  选了: 京都漫画风
  否决: 美漫风（太硬，不适合柔情戏）
  理由: 主角性格内向，京都风的留白契合
}
```

#### 3.3.2 语法元素清单

| 块类型 | 用途 | 派生到 |
|---|---|---|
| `@角色 NAME { ... }` | 定义可复用的角色 | 👥 角色子画布的卡片 |
| `@场景 NAME { ... }` | 定义可复用的场景 | 🌍 场景子画布的卡片 |
| `@镜头 NUM { ... }` | 定义一个镜头 | 🎬 分镜子画布的节点 |
| `@对白 A → B: TEXT` | 角色对话 | 镜头节点的 dialog 字段 + 时间轴字幕 |
| `@关系 { A ↔ B: ... }` | 实体之间的语义关系 | 子画布之间的关联边 |
| `@决策 NAME { ... }` | 创作决策日志 | 项目记忆，不渲染节点但可被 Agent 查询 |
| `@风格 NAME { ... }` | 定义可复用的视觉风格 | 🎨 风格子画布卡片 |
| `@道具 NAME { ... }` | 定义可复用道具（可选，v0.7+） | 自定义分类 |
| `@音轨 NAME { ... }` | 定义音乐/SFX | 🎵 声音子画布 |

#### 3.3.3 编辑器交互

**写法 A：Slash command**
- 在编辑器里输入 `/角色`，弹出表单 → 填写后插入完整 `@角色 NAME { ... }` block
- 适合新手

**写法 B：直接键入**
- 用户输入 `@角色 小苏 {`，编辑器自动补全 `}` 并切换到 block 编辑模式
- 适合熟手

**写法 C：Block 折叠**
- 写完后 `@角色 小苏 { ... }` 在 TipTap 里渲染成一张紧凑的卡片（折叠态），点击展开编辑
- 视觉舒服

#### 3.3.4 渐进采用

**不强制结构化**：用户可以继续写自由 markdown，结构化 block 只是可选叠加。
- 入门：纯 markdown 写大纲
- 进阶：加 `@角色` block 后体验角色一致性
- 老手：全篇结构化 + `@决策` 日志

### 3.4 双向绑定

**剧本 → 画布**：写 `@角色 小苏 { ... }` → 角色子画布即时出现/更新小苏卡片

**画布 → 剧本**：在角色子画布编辑小苏的卡片（改了描述、加了参考图）→ 剧本里 `@角色 小苏 { ... }` block 内容自动更新

**冲突解决**：双向同步 vs 真理源 (source of truth) 的经典问题
- **真理源 = 剧本** （文本永远优先）
- 画布是文本的**派生视图**，画布上的编辑是对 AST 的修改，再 serialize 回文本
- 文件锁机制：画布操作期间，剧本的对应段落 readonly
- 冲突时弹出 diff 让用户选

---

## 4. 默认分类清单

经过推敲，**8 个默认分类**：

### 4.1 必备 6 个（创作主线）

| # | 分类 | 图标 | 内容类型 | 平均规模 |
|---|---|---|---|---|
| 1 | 故事 | 📖 | 单文档 (TipTap + Nomi Script) | 1 |
| 2 | 角色 | 👥 | 角色卡（带 LoRA / 参考图 / 描述） | 2-8 |
| 3 | 场景 | 🌍 | 场景卡（带光线 / 风格参考 / 道具列表） | 3-10 |
| 4 | 风格 | 🎨 | 单画布（配色 + 风格参考 + global LoRA） | 1 |
| 5 | 分镜 | 🎬 | 镜头节点（image/video kind）+ 时序连边 | 6-50 |
| 6 | 声音 | 🎵 | 音频文件（BGM / 配音 / SFX） | 3-15 |

### 4.2 工具性 2 个（流转必需）

| # | 分类 | 图标 | 用途 |
|---|---|---|---|
| 7 | 资源池 | 🖼️ | 用户从外部拖入的图片 / 视频，等待归类 |
| 8 | 导出 | 📦 | 渲染输出的成片版本 |

### 4.3 用户可加（自定义）

支持用户新建分类，需要提供：
- 名称 + 图标 + 颜色
- "视图模板"：网格卡片 / 列表 / 自由画布 / TipTap 文档
- "默认资产种类"：image / video / audio / text / 自定义

常见自定义分类示例：
- 🎭 道具
- 💡 灵感参考
- 🧠 决策日志
- 📊 数据 / 统计
- 🎤 配音稿

### 4.4 为什么是这 8 个不是 5 个或 12 个

**< 6 个不够**：割裂感不强，分类的价值显不出来
**> 10 个太碎**：用户负担过重，每个分类资产太少没意义

**8 个的内部逻辑**：
- 主线 6 个对应"故事 → 选角 → 选景 → 定风格 → 拍摄 → 配乐"的标准制片流程
- 工具性 2 个对应"入流 → 出流"
- 自定义留口子让重度用户扩展

### 4.5 默认分类的可选可禁用

每个项目可以决定开启哪些分类。新建项目时给出 3 种模板：
- **漫剧短片**：故事 + 角色 + 场景 + 分镜 + 声音 + 资源池 + 导出 (7 个)
- **产品 Demo**：故事 + 风格 + 分镜 + 资源池 + 导出 (5 个)
- **自由创作**：仅故事 + 资源池 + 导出 (3 个)
- **完整**：8 个全开

---

## 5. Nomi Script 语法详细规范

### 5.1 基本块语法

```
@<块类型> [<名称或编号>] [{
  <字段>: <值>
  ...
}]
```

- 名称大小写敏感
- 字段名固定 (内置) 或自定义 (用户扩展)
- 值可以是字符串、数字、引用 (`img:xxx` / `角色.NAME` / `场景.NAME`)、列表 (`[a, b, c]`)

### 5.2 引用语法

| 写法 | 含义 |
|---|---|
| `角色.小苏` | 引用一个已定义的角色 |
| `场景.咖啡馆` | 引用一个已定义的场景 |
| `镜头.5` | 引用编号 5 的镜头 |
| `img:asset-id-abc` | 引用项目内的图片资产 |
| `style.京都漫画` | 引用一个风格 |

### 5.3 关系语法

```
@关系 {
  A ↔ B: TEXT     # 双向关系
  A → B: TEXT     # 单向关系
  A ⇒ C: TEXT     # 习惯/属性关系
}
```

派生为子画布之间的 `relationship` 边，鼠标 hover 显示 TEXT。

### 5.4 错误处理

- 引用未定义的实体 → 编辑器红色波浪线 + 快速修复"创建此角色"
- 字段类型不匹配 → 警告 + 默认值兜底
- 重复定义 → 警告，第二次定义覆盖

### 5.5 解析时机

- TipTap 编辑器输入时 lazy parse（防抖 300ms）
- 解析结果增量更新对应子画布（diff 比对，只改变化的部分）
- 严重错误（如循环引用）不影响其他 block 解析

### 5.6 文件持久化

剧本最终保存为：
```
{projectId}/
  project.json (原有元数据)
  story/
    main.nomi    (Nomi Script 主文件，纯文本)
    main.ast.json (派生 AST，可重建)
  characters/   (派生角色卡，但 source of truth 在 main.nomi)
  scenes/
  ...
```

`.nomi` 是纯文本可 Git 化，可被外部工具读写。

---

## 6. 每个子画布的专属能力详述

### 6.1 📖 故事子画布

**视图**：全屏 TipTap，左 70% 编辑器，右 30% 大纲 outline

**专属能力**：
- Nomi Script block 渲染（折叠态卡片 + 展开态表单）
- Slash command 插入 block
- 实时 AST 解析 + 引用检查
- 大纲面板：自动列出所有 `@角色 / @场景 / @镜头`，点击跳转
- "拆镜头 Agent"按钮（呼应 PRD §10 C2）

### 6.2 👥 角色子画布

**视图**：响应式卡片网格（默认 4 列）

**每张角色卡显示**：
- 名称（大字）
- 主参考图（如已生成）
- 简短描述（前 80 字）
- 引用计数徽标："在 12 个镜头中出现"
- 编辑按钮

**专属操作**：
- 双击卡片 → 全屏编辑（直接同步回剧本）
- 右键 "在分镜中查找" → 跳到分镜子画布并高亮所有用到此角色的节点
- 拖角色卡到任何画布的节点上 → 自动添加 `character_ref` 边
- 批量"生成参考图"：选中多个角色卡 → 一键 AI 生成

### 6.3 🌍 场景子画布

**视图**：网格卡片 + (可选) 地图视图 / 平面图视图

**专属能力**：
- 每张场景卡有 360° panorama 槽
- 场景之间可连边表示"切换" 或 "相邻"
- "在此场景的所有镜头" 视图：场景卡展开 → 镜头列表

### 6.4 🎨 风格子画布

**视图**：单画布，分为三区
- 上：配色板（取色器 + 调色板）
- 中：风格参考图网格（用户拖入或 AI 生成）
- 下：全局 LoRA / 提示词配置

**专属操作**：
- 拖颜色到任何节点 → 加入该节点的 prompt 上下文
- "应用风格到整个项目"：触发 batch update 所有 `@镜头`

### 6.5 🎬 分镜子画布

**视图**：当前 generationCanvas 画布（不大改）

**新增能力**：
- 节点自动按"时序连边"的 topological order 在画布上从左到右排列
- 节点上叠加镜头编号徽标 (1, 2, 3, ...)
- 顶部 "整条故事板预览" 条：所有节点的缩略图水平排列，点击跳转到对应节点
- "发送整个故事板到时间轴"按钮（已有 send-to-timeline，扩展为"全部"）

### 6.6 🎵 声音子画布

**视图**：列表 + 波形预览

**专属能力**：
- 文件级元数据：时长、采样率、情绪标签
- 拖到时间轴 audio track（新增 audio track 概念，依赖 ffmpeg export 升级）
- AI 生成：选择风格 → 调用音频生成 provider（Suno、ElevenLabs 等）

### 6.7 🖼️ 资源池

**视图**：平铺网格，可切多种密度

**专属操作**：
- 多维筛选：日期 / 来源（用户导入/AI 生成）/ 类型 / 关键词
- "归类到 …" 右键菜单
- 自动整理：Agent 可建议"这些图片像场景参考，要不要归到场景子画布？"

### 6.8 📦 导出

**视图**：列表，每行一个导出版本

**字段**：渲染日期、profile（9:16/16:9/1:1）、文件大小、状态、分享链接

**操作**：在文件管理器中打开 / 复制路径 / 上传到云

---

## 7. 关系图谱

### 7.1 关系类型

| 关系 | 来源 | 视觉 |
|---|---|---|
| 角色出现在镜头 | `@镜头.角色: [小苏]` | 角色卡 → 镜头节点的实线 |
| 镜头发生在场景 | `@镜头.场景: 咖啡馆` | 场景卡 → 镜头节点的虚线 |
| 风格应用于镜头 | `@镜头.风格: 京都漫画` 或全局 | 风格卡 → 镜头节点的彩色细线 |
| 角色之间关系 | `@关系 { A ↔ B: ... }` | 角色卡之间的关系边，hover 显示 TEXT |
| 决策影响选择 | `@决策` 引用其他实体 | 决策卡 → 受影响实体（不渲染线，记录在 Memory 里） |

### 7.2 关系视图

**"全景模式"切换**：左下角一个按钮，把所有子画布合并显示为一个大图谱，所有关系都可见。
- 这是给用户**"鸟瞰整个项目"**的能力
- 也是给 Agent 输入项目结构时的视图

**布局算法**：Force-directed 自动布局，主角色为锚，关系边作为引力

### 7.3 关系作为 AI 上下文

当 Agent 处理一个镜头时，自动收集：
- 该镜头的所有关联角色卡（含 LoRA、参考图）
- 该镜头的场景卡（含光线、风格）
- 该项目的全局风格
- 上下镜头的内容（前后镜头）

这就是 Nomi 给 AI 的"项目记忆"，远超 prompt 工程能做的事。

---

## 8. UI/UX 设计

### 8.1 总体布局

```
+--------+---------------------------------------------+
| Topbar (项目名 + 创作/生成/预览 段控制器 + 模型接入)
+--------+---------------------------------------------+
|        |                                             |
| 目录树 |          当前子画布的主内容                  |
| 60px   |                                             |
| 收起   |                                             |
| 200px  |                                             |
| 展开   |                                             |
|        |                                             |
|        |                                             |
+--------+---------------------------------------------+
| 时间轴（跨所有子画布全局可见）                         |
+----------------------------------------------------+
```

### 8.2 目录树细节

**默认收起态 (60px 宽)**：
- 只显示图标 + count 徽标
- hover 显示分类名

**展开态 (200px 宽)**：
- 图标 + 名称 + 数量
- 可拖拽排序
- 右键：重命名、改图标、改颜色、删除（仅自定义）
- 底部：`+ 新分类`

**Active 分类**：彩色高亮 + 左边描边

### 8.3 子画布切换动画

- 平移过渡（左/右滑入）+ 淡入淡出
- 时长 200ms
- 切换时主画布的 zoom/offset 各分类独立保存

### 8.4 跨子画布拖拽

最关键的 UX：从一个子画布把卡片"拖到"另一个子画布
- 拖动时屏幕上出现一个"小幽灵"跟随光标
- 目录树相应分类高亮成 drop target
- 松手 → 切换到目标分类，新位置高亮闪烁
- 自动建立 reference 关系

---

## 9. 数据模型

### 9.1 项目结构升级

```typescript
type Project = {
  id: string
  name: string
  // ... existing fields ...
  categories: Category[]   // NEW
  ast: NomiScriptAST | null  // NEW: 派生自 story/main.nomi 的 AST
}

type Category = {
  id: string
  name: string
  icon: string
  color?: string
  order: number
  viewType: 'document' | 'card-grid' | 'graph-canvas' | 'list' | 'waveform'
  isBuiltin: boolean      // true for the default 8
  isHidden: boolean       // user can hide built-ins
}

type GenerationCanvasNode = {
  // ... existing fields ...
  categoryId: string      // NEW: which sub-canvas this node lives in
  derivedFrom?: {         // NEW: 派生自剧本的实体
    nomiBlock: 'character' | 'scene' | 'shot' | ...
    blockId: string       // 对应 AST 节点 ID
  }
}
```

### 9.2 文件布局

```
~/Documents/Nomi Projects/未命名漫剧 06_01/
  project.json          (元数据 + categories 列表)
  story/
    main.nomi           (Nomi Script 源文件 — source of truth)
    main.ast.json       (派生 AST，性能缓存)
  characters/           (派生角色卡 JSON，可重建)
  scenes/
  shots/                (== generationCanvas nodes 的当前位置)
  audio/
  assets/               (导入素材原文件)
  exports/
  cache/
  logs/
```

### 9.3 AST 设计

```typescript
type NomiScriptAST = {
  blocks: NomiBlock[]
  references: Reference[]
  diagnostics: Diagnostic[]
}

type NomiBlock = {
  id: string             // 文件内偏移 + hash
  kind: 'character' | 'scene' | 'shot' | 'style' | 'relation' | 'decision' | ...
  name?: string
  fields: Record<string, NomiValue>
  span: { start: number; end: number }  // 在源文件中的位置
}

type NomiValue =
  | { type: 'string'; value: string }
  | { type: 'number'; value: number }
  | { type: 'ref'; target: { kind, name } }
  | { type: 'list'; items: NomiValue[] }
```

### 9.4 同步引擎

**核心同步规则**：
1. 文本变化 → AST 重算 → diff(old AST, new AST) → 应用到 categories/nodes
2. 卡片变化 → 修改 AST 节点 → serialize 回文本（保留原文格式 / 注释）
3. 冲突时：文本胜，提示用户手动 review

**性能**：
- AST 解析使用 tree-sitter 或 chevrotain（增量解析友好）
- 大型项目（500+ block）首次解析 < 200ms

---

## 10. AI Agent 集成

### 10.1 新增 Agent 工具

```typescript
// 现有 (Phase B):
read_canvas_state
create_canvas_nodes
connect_canvas_edges
set_node_prompt
delete_canvas_nodes

// 新增 (Phase G):
read_project_structure       // 读取整个项目的分类 + 关系图谱
read_nomi_script             // 读取剧本源文件 + AST
update_nomi_script           // 写入剧本（受确认门控）
list_category_items          // 列出某个分类下的所有项
create_character_card        // 创建角色卡（更新剧本对应 @角色 block）
create_scene_card            // 创建场景卡
suggest_relationship         // Agent 建议 A 和 B 之间的关系
query_references             // 查询某个实体在哪里被引用
```

### 10.2 新增 Skill Pack

| Skill key | 用途 |
|---|---|
| `workbench.script-writer` | 把用户的散文剧本改写为 Nomi Script 格式 |
| `workbench.character-bible` | 从已有镜头反推角色一致性问题，建议补全角色卡 |
| `workbench.scene-designer` | 给一个场景写氛围 / 光线 / 风格描述 |
| `workbench.continuity-checker` | 检查跨镜头的角色一致性、场景连续性、风格匹配度 |

### 10.3 Agent 心智从"无 context" 升级为"项目记忆原生"

**旧：**
```
用户：生成第 5 个镜头
Agent：（用户没说参考什么）
```

**新：**
```
用户：生成第 5 个镜头
Agent：（读 read_nomi_script → 镜头 5 在咖啡馆，角色小苏，景别中景，
         读 read_project_structure → 小苏 = anime-girl-v2 LoRA + 白衬衫 ref，
         咖啡馆 = 暖黄 4500K + 京都漫画风格，
         前后镜头 4/6 上下文）
        → 一次性生成高质量、一致性强的镜头 5
```

这就是"项目记忆作为护城河"的真正实现。

---

## 11. 自定义扩展

### 11.1 用户定义分类

通过 UI：
1. 点 `+ 新分类`
2. 填名称 / 图标 / 颜色
3. 选视图模板：单文档 / 卡片网格 / 自由画布 / 列表
4. （高级）声明 schema：这个分类的卡片有哪些字段

通过文件：
- 在 `~/.config/nomi/categories.json` 配置全局默认分类集合
- 或在项目里 `project.json` 里覆写

### 11.2 用户定义 Nomi Script block

- Skill Pack 可以注册新的 block 类型，如 `@道具` / `@配音` / `@镜头风格`
- skill.json 增加 `nomiBlocks: [...]` 声明
- 解析器在加载 skill 后自动支持

### 11.3 模板项目

社区 / 官方提供模板：
- "AI 漫剧短片模板"（含 8 个默认分类 + 范例剧本）
- "产品 demo 模板"
- "动画样片模板"

`.nomiproj` 文件可作为模板分发。

---

## 12. 迁移策略

### 12.1 现有扁平项目

第一次打开升级版 Nomi 的旧项目时：
1. 弹窗"项目结构升级"，描述变化
2. 自动按 `node.kind` 分类：
   - `text` / `character` → `角色` 分类 (轻度判断)
   - `image` / `keyframe` → `分镜` 分类
   - `video` → `分镜` 或 `导出` (依赖 status)
   - `panorama` → `场景` 分类
   - `output` → `导出` 分类
   - 其他 → `资源池`
3. 不创建 Nomi Script — 用户的旧 markdown 留在故事子画布
4. 在 `decisions/` 里记录"自动迁移于 2026-06-XX"

### 12.2 回退保险

升级前自动备份完整项目 → `cache/backup-pre-v0.5/`
用户可在 30 天内一键回退

---

## 13. 路线图

### Phase E: 项目目录基础 (v0.5, 4 周)

**目标**：用户能切换子画布并看到分类，但分类还是手动建立。

任务：
- E1: 数据模型升级（Category 表 + node.categoryId 字段 + 迁移逻辑）
- E2: 目录树 UI 组件 + 收起/展开
- E3: 子画布切换 + 状态保持
- E4: 默认 6 分类（不含声音 / 导出，先简化）
- E5: 资源池视图（卡片网格 + 筛选）
- E6: 节点拖到目录树分类的归类操作
- E7: 自动迁移现有项目
- E8: 项目模板（漫剧 / Demo / 自由 三个模板）

**验收**：用户能：新建漫剧模板项目 → 看到 6 个分类 → 在每个分类里独立工作 → 资源池里的素材能拖到分镜分类。

### Phase F: Nomi Script 结构化语法 (v0.6, 5 周)

**目标**：用户能在故事分类用结构化语法写剧本，自动派生角色 / 场景 / 分镜卡片。

任务：
- F1: Nomi Script 语法定义 + 解析器
- F2: TipTap 编辑器扩展 (block 渲染 + slash command + 自动补全)
- F3: AST → Categories/Nodes 派生引擎
- F4: 双向绑定（卡片编辑回填 AST → 文本）
- F5: 角色卡 UI (👥 分类)
- F6: 场景卡 UI (🌍 分类)
- F7: 风格分类 UI (🎨)
- F8: 引用检查 + 错误诊断
- F9: 单元测试 + e2e

**验收**：用户写 `@角色 小苏 { 外观: ... }` → 角色子画布即时出现卡片 → 编辑卡片 → 文本同步更新。

### Phase G: 关系图谱 + AI 集成 (v0.7, 4 周)

**目标**：Agent 有了项目记忆原生上下文，关系图谱可视化。

任务：
- G1: 关系数据模型 + Edge 类型扩展
- G2: 全景模式视图（force-directed 布局）
- G3: 新增 Agent 工具集 (read_project_structure 等)
- G4: 4 个新 skill (script-writer / character-bible / scene-designer / continuity-checker)
- G5: 跨子画布拖拽 (drag character → shot)
- G6: 引用计数徽标 + 跳转
- G7: 声音 / 导出分类的完整实现
- G8: 用户自定义分类
- G9: AI 自动归类资源池建议

**验收**：用户问 Agent "生成镜头 5" → Agent 自动收集 镜头 5 的剧本上下文 + 角色 + 场景 + 风格 → 一次性输出高质量 prompt。

---

## 14. 风险与对策

### 风险 1：学习曲线
**问题**：8 个分类 + 新语法可能让新用户不知所措。
**对策**：
- 默认折叠空分类，只显示有内容的
- "新建项目"必走模板向导
- 完整 onboarding 教程视频

### 风险 2：双向绑定的复杂度
**问题**：文本和图谱双向同步是分布式系统级难题。
**对策**：
- 严格选定 "文本=真理源"
- 图谱编辑用 "delta 应用到 AST" 模型
- 冲突时显式提示用户，不自动合并

### 风险 3：分类太多反而碎片化
**问题**：每个分类 1-2 个资产时反而看起来空荡荡。
**对策**：
- 折叠空分类
- 资产 < 3 个时不显示分类
- 默认提供"全景模式"作为出口

### 风险 4：Nomi Script 太私有
**问题**：用户在 Nomi 里写的剧本能不能拿出来用？
**对策**：
- Nomi Script 是开源 spec（写一份独立 spec 文档）
- 提供 CLI: `nomi-script parse story.nomi → JSON`
- 支持导出为 Fountain 标准（业界格式）

### 风险 5：性能
**问题**：500+ 镜头项目的 AST 解析 + 派生 + 渲染会卡。
**对策**：
- AST 增量解析（tree-sitter）
- 派生引擎用 diff 策略只更新变化节点
- 大项目时分类懒挂载

### 风险 6：与现有 Agent 协议冲突
**问题**：Phase B 已经有 5 个 canvas tools，新增工具集是不是要重新设计 Agent 协议？
**对策**：
- 新增工具走同样 Vercel AI SDK tool calling 协议
- 不破坏现有 tools，只是扩充
- Skill Pack v2 manifest 自然支持

---

## 15. 跨文档关系

| 文档 | 角色 |
|---|---|
| 本文档 | 结构化创作 + 项目目录的产品定义 |
| `nomi-product-prd-v2-2026-05-23.md` | 战略大盘 — 本 PRD 是支柱 3 + 支柱 4 的落地形态 |
| `nomi-agent-migration-plan-2026-05-23.md` | Agent 基础 (Phase A-D) — 本 PRD 的 Phase G 在它之上扩展 |
| `nomi-agent-tech-audit-2026-05-23.md` | Agent 技术基础 |
| `nomi-differentiation-prd-2026-05-23.md` | 早期差异化分析 |

**版本关系**：
- v0.4.0：Agent 基础设施（当前正在 final audit）
- **v0.5.0：Phase E 项目目录** (本 PRD)
- v0.6.0：Phase F Nomi Script (本 PRD)
- v0.7.0：Phase G 关系图谱 + AI 项目记忆 (本 PRD)
- v0.8.0+：模板社区 / 协作 (v2 PRD 后期)

---

## 16. 结语：为什么这是 Nomi 的关键

回到 v2 PRD 的核心命题：

> Nomi 是创作者的**数据主权工作台**：你的故事、角色、素材、prompt、模型证据和工作流记忆都沉淀在一个可迁移的本地项目里，并能继续驱动下一次创作。

**目录树 + 结构化剧本不是 UI feature — 它就是"数据主权"这件事的真正形态**。没有它，Nomi 的项目仍然是"一个文件夹 + 一堆 JSON"。有了它，Nomi 的项目是**"一份带类型的剧本 + 自动派生的资产图谱"**。

这是 Figma 进不来的方向，因为 Figma 没有"角色 / 场景"领域模型。
这是 Krea 进不来的方向，因为 Krea 没有本地项目持久化。
这是 ComfyUI 进不来的方向，因为 ComfyUI 是节点工程，不是创作流程。
这是 Final Draft 进不来的方向，因为 Final Draft 不会生成视觉资产。

**Nomi 是唯一能把这四件事融合的产品**。

接下来 12 周（Phase E + F + G）就是要把它做出来。
