{"owner":"chatfire-AI","repo":"huobao-drama","hasSkills":true,"totalSkillsCount":8,"totalTokensCount":11549,"categories":["anthropic-skill","claude-rule"],"hasMcp":false,"mcpConfig":null,"found":["backend/workspace/skills/prompt-generator/video-prompt/SKILL.md","backend/workspace/skills/script-rewriter/SKILL.md","backend/workspace/skills/prompt-generator/prop-prompt/SKILL.md","backend/workspace/skills/prompt-generator/character-prompt/SKILL.md","backend/workspace/skills/prompt-generator/scene-prompt/SKILL.md","backend/workspace/skills/extractor/SKILL.md","backend/workspace/skills/storyboard-breaker/SKILL.md","CLAUDE.md"],"skills":{"backend/workspace/skills/prompt-generator/video-prompt/SKILL.md":"---\nname: video-prompt\ndescription: 视频提示词规范 — 根据分镜段落内容生成按时间分段、段内可切镜的视频生成提示词\n---\n\n# 视频提示词（分镜段落 → video_prompt）\n\n根据单个分镜段落的 description（含【镜头N】子镜头结构与台词/旁白）/ atmosphere / duration，生成驱动 AI 视频生成的 `video_prompt`。**一个分镜段落 = 一段 8-15 秒的视频，内部允许切镜**：段与段之间可以是不同镜头（换景别/角度/对象），用硬切衔接；但**全程不跨场景**、不闪回。\n\n## 格式\n\n`video_prompt` 的**第一行是信息头**：先介绍这条视频有哪些人物和场景，然后再接时间分段。人物、场景一律用 @ 引用（生成时会替换为对应参考图片标记，让视频模型先对上\"谁\"和\"在哪\"）。\n\n```\n出场人物：@小明、@小红；场景：@咖啡厅。\n0-3秒：@咖啡厅，近景固定镜头，@小明低头看手机，手指反复敲桌面，表情焦虑。\n3-6秒：切到门口全景，门铃响，@小红推门走入，带进一阵冷风。\n6-9秒：切回中景，@小红微笑着走向小明坐下，小明说：「你终于来了。」\n```\n\n信息头规则：\n- 只列该分镜段落实际出场的人物和绑定的场景，不要列没出场的\n- 有明显道具出场时可在信息头追加（如 `；道具：@信件`）\n- 信息头独立一行，以句号结尾，之后是时间分段\n\n按 3 秒为一段，每段单独一行、用换行分隔，时间范围连续衔接（无重叠、无空缺）。\n\n## 与分镜描述的映射\n\n`description` 是 video_prompt 的唯一内容来源（画面、动作、台词、旁白都在其中），转换规则：\n\n- `description` 的每个 `【镜头N】` 映射为 **1-2 个连续的 3 秒段**，顺序一致、不遗漏、不合并、不新增子镜头\n- 台词/旁白从对应 `【镜头N】` 内的「角色名说：「…」」「旁白：…」提取，分配到该子镜头映射的段；**不要创作 description 之外的新台词**\n- 画面动作以 `description` 为准；`atmosphere` 只用于补各段的光线、色调与氛围描写\n\n## 段内结构\n\n每一段按此顺序组织内容（可省略无内容的项，但动作/画面必须有）：\n\n**时间范围 ＋ 场景@引用 ＋ 景别/运镜 ＋ 角色@引用＋主体动作·表情 ＋ 对白/旁白 ＋ 氛围光线**\n\n- **第一段必须建立空间**：场景 + 机位 + 角色的位置与状态，让观众一眼知道在哪、看谁\n- **切镜**：切镜后的段开头用\"切到/切回\"等衔接词，并重新交代景别与主体；切镜点应对齐分镜 `description` 中的 `【镜头N】` 结构\n- **景别/运镜**：每段一个镜头状态（近景/中景/全景/特写；固定/推/拉/摇/跟）；单个子镜头内运镜连续，切镜后可更换运镜方式\n- **动作**：每段一个主动作，动词具体可见（走、转身、抬头、攥紧、停顿）\n- **情绪全部转为可见描写**：不要\"他很伤心/气氛紧张\"这类抽象词，写成\"他低下头、手指攥紧杯沿、呼吸变重\"\n- **对白/旁白**：写「角色名说：「台词」」，旁白写「旁白：内容」；3 秒念不完的长台词拆到多段；无对白的段可写环境音/动作音（如\"机器持续轰鸣\"）\n\n## 引用规则\n\n- `@场景名` — 场景引用，名字必须与场景列表中的地点完全一致\n- `@角色名` — 角色引用，名字必须与角色列表中的名字完全一致\n- `@道具名` — 道具引用，名字必须与道具列表中的名字完全一致；道具在画面中明显可见、被使用或特写时引用\n- 生成时会自动把 `@名字` 替换为对应参考图片标记（如 `@小明` → `@图片1小明`），因此名字必须精确匹配，不要缩写或加额外符号\n- **每段至少一个 @ 引用锚定画面**；角色出场的段必须 @ 该角色；只引用该分镜段落已绑定的场景/角色/道具\n\n## 时间轴规则\n\n- 段数 = 分镜段落 duration ÷ 3 秒（向上取整），各段时间范围相加必须等于段落总时长\n- 内容节奏：第一段建立 → 中段推进动作/冲突 → 末段落到结果或情绪点\n\n## 禁止事项\n\n- 跨场景切换、闪回（一个段落只发生在一个场景内）\n- 引用列表之外的场景/角色名\n- 抽象心理描写、文学化比喻（模型只认可见画面）\n- 语言与会话语言指令不符\n\n## 保存\n\n调用 `update_storyboard` 仅更新该分镜段落的 `video_prompt` 字段，不要改动其他字段，不要重新拆分整集。\n","backend/workspace/skills/script-rewriter/SKILL.md":"---\nname: script-rewriter\ndescription: 小说改写为格式化剧本的方法论和规范\n---\n\n# 剧本改写指南\n\n## 改写原则\n\n1. **保留核心情节**：不改变主线故事和角色关系\n2. **增强画面感**：将叙述性文字转化为可视化的场景描写\n3. **对话驱动**：用对白推动情节，减少旁白\n4. **节奏把控**：每场戏控制在 30-60 秒，适合短视频\n5. **不写镜头语言**：不涉及景别、角度、运镜，这些属于分镜拆解步骤\n\n## 格式化剧本格式\n\n```\n## S01 | 内景 · 咖啡厅 | 黄昏\n\n黄昏的光线透过落地窗洒进咖啡厅，吧台上咖啡杯热气升腾。\n\n小明独自坐在角落卡座，低头看手机，神情有些焦虑。\n\n门铃响起，小红推门而入。她看到小明，微笑着走过去。\n\n小红：（微笑）等很久了吗？\n小明：（抬头）还好，刚到。\n```\n\n### 格式规则\n\n- `## S编号 | 内景/外景 · 地点 | 时间段` — 场景头\n- 动作描写自然段 — 不包含任何镜头语言\n- `角色名：（状态/表情）台词内容` — 对白格式\n\n### 内容量参考\n\n格式化剧本相比原始内容增加约 20-30%，主要增量是场景头标记和对白格式化，不是扩写。\n\n## 改写步骤\n\n1. 先调用 `read_episode_script` 读取原始内容\n2. 分析内容结构（对话、叙述、心理描写的比例）\n3. 调用 `rewrite_to_screenplay` 执行改写\n4. 检查改写结果，确认符合格式化剧本格式\n5. 调用 `save_script` 保存最终结果\n\n## 注意事项\n\n- 心理描写可转化为角色表情/动作或画外音\n- 长段叙述拆分为多个短场景\n- 确保每个场景有明确的情绪转折点\n- 保持角色语言风格一致性\n- 场景编号连续递增（S01, S02, S03...）\n- 时间段要具体（黄昏、深夜、清晨），不要笼统写\"白天\"\n","backend/workspace/skills/prompt-generator/prop-prompt/SKILL.md":"---\nname: prop-prompt\ndescription: 道具最终提示词规范 — 白底单品静物，标准产品摄影视角：比例准确、边缘完整、背景不承载叙事\n---\n\n# 道具最终提示词（白底单品 · 标准产品摄影）\n\n生成的是一张白底单品图（product shot）：**采用标准产品摄影视角**，画面中只有道具本身，孤立放置在纯白背景上，**不掺杂任何其他元素**——没有其他物品、没有人物、没有场景环境、没有手部持握。\n\n三条硬性要求：\n1. **物品各部分比例准确**——不要夸张、变形或风格化拉伸，道具的相对尺寸关系必须真实\n2. **边缘完整**——道具整体完整入镜，四周留白，任何部分都不得被画面边缘裁切\n3. **背景不承载任何叙事内容**——纯白背景只是衬底，不带场景感、不带情节暗示、不带装饰元素\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n单品产品图，标准产品摄影视角，[道具名 + 材质/颜色/形状/大小 + 新旧程度与磨损细节]，\n物品各部分比例准确，孤立放置在纯白背景上，居中完整入镜，边缘完整无裁切，\n背景纯净不承载任何叙事内容，无其他物品、无人物、无场景，\n柔和均匀的影棚光，轻淡阴影，高细节\n```\n\n## 生成规则\n\n- 以道具 `name`（名称）与 `description`（物品外貌）为核心：材质、颜色、形状、大小、新旧程度、磨损痕迹等物理细节**逐项落地**，这是道具辨识度的来源\n- 标准产品摄影视角：微俯视 3/4 视角（同时看清顶面与侧面，最有立体感）；扁平道具（纸张、证件、照片）用正俯视平铺\n- 单品居中完整呈现，四周留白，比例准确、边缘完整，不要裁切道具主体\n- 柔和均匀的影棚光，阴影轻淡，高细节\n- 只描写物品本身，不要提及剧情、角色或用途（背景与画面都不承载叙事内容）\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇；**不要**\"电影质感\"类词汇（道具图是产品图不是剧照）\n\n## 禁止事项\n\n- 手部持握、人物、其他物品、场景环境入镜\n- 包装、底座、展示架（除非它就是道具本体的一部分）\n- 文字、水印、签名（道具本体上印刷的文字图案可以保留并描述）\n- 环境反光、彩色光\n- 夸张透视、变形、比例失真、边缘裁切\n\n## 保存\n\n调用 `save_prop_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","backend/workspace/skills/prompt-generator/character-prompt/SKILL.md":"---\nname: character-prompt\ndescription: 角色最终提示词规范 — 正脸特写 + 三视图（character turnaround：正面/90 度侧面/背面），作为后续所有生成的形象锚点\n---\n\n# 角色最终提示词（左侧正脸特写 + 右侧三视图）\n\n生成的是一张角色设定参考图（character reference sheet），构图固定为：\n\n- **左侧：正脸特写**——头部与肩部的正面近景，五官、发型、肤质清晰可见，作为脸部辨识度的锚点\n- **右侧：并列展示正面、90 度侧面、背面三张等高全身视图**——同一角色的三个全身视图等高并排，头顶与脚底对齐\n\n**核心原则：一致性 > 美观。** 这张图是后续所有角色图片、视频参考的形象锚点，必须中性、清晰、可复用——不要追求单张图的艺术感。\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n角色设定参考图，左侧为正脸特写，右侧并列展示正面、90 度侧面、背面三张等高全身视图，\n特写与全身视图都是同一角色，全身入镜，中性 A 字站姿，三张全身视图等高并排、头顶脚底对齐，\n[年龄感 + 性别感 + 体态]，[五官特征]，[发型]，[服装 + 配饰]，\n正脸特写与三个视图的脸、发型和服装完全一致，\n纯白背景，柔和均匀的光线，电影质感\n```\n\n## 描述顺序规则\n\n把**最有辨识度的特征放在前面**，按此顺序落地 `appearance`（样貌）与 `styling`（妆造）的每个关键元素，不遗漏：\n\n1. 身份锚点：年龄感（如\"二十出头\"）、性别感、体态（高矮胖瘦、姿态习惯）\n2. 五官：脸型、眼睛、其他显著特征（疤、痣、眼镜等）——正脸特写尤其依赖这部分描写\n3. 发型：颜色、长度、样式\n4. 服装：款式、颜色、材质、状态（如\"袖口有焊锡痕迹的皱褶工服\"）\n5. 配饰：只写有辨识度的，不堆砌\n\n角色的性格特点要转化为外在气质与神态描写（如\"憔悴\" → \"眼神疲惫、肩膀微垮\"），不要直接出现性格词汇。\n\n## 构图与一致性\n\n- 左侧正脸特写：正面朝向镜头、中性表情、头顶到肩膀完整入镜\n- 右侧三张全身视图：同一角色的正面、90 度侧面、背面，**等高并排、间距均匀**，头顶与脚底在同一水平线上\n- 特写与三张全身视图必须是同一张脸、同一发型、同一服装——明确写出\"正脸特写与三张全身视图的脸、发型和服装完全一致\"\n- 中性站姿、自然表情——方便作为参考图复用\n- 柔和均匀的棚拍光，不要戏剧性光影（参考图要在各种场景下都能用）\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇\n\n## 禁止事项\n\n- 动态姿势、夸张表情、手持道具、与他人同框\n- 裁切身体（全身视图必须 full body，头顶到脚底完整入镜；特写必须头部肩部完整入镜）\n- 文字、标签、水印、签名\n- 重阴影、彩色背景光、背景道具\n\n## 保存\n\n调用 `save_character_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","backend/workspace/skills/prompt-generator/scene-prompt/SKILL.md":"---\nname: scene-prompt\ndescription: 场景最终提示词规范 — 清晰广角建立镜头：前景/中景/后景/出入口/地面/墙面/主要陈设的固定相对位置，空间连续自洽可复用，无人物\n---\n\n# 场景最终提示词（广角建立镜头 · 无人物空镜）\n\n生成的是一张**清晰的广角建立镜头（establishing shot）**场景图：**完全没有人物**的纯场景空镜，完整展示**前景、中景、后景、出入口、地面、墙面及主要陈设的固定相对位置**，空间结构连续、自洽且可复用。\n\n这张图会作为该场景所有镜头的背景参考锚点：观众和模型都必须能从这张图读懂整个空间的布局——从哪里进出、地面与墙面是什么质感、核心陈设各自固定在什么位置。视角必须稳定、通用。\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n固定机位广角镜头，清晰的建立镜头，[地点 + 年代质感]，[时间段]，\n前景（[前景元素]）、中景（[中景主体空间]）、后景（[后景纵深]）三层分层构图，\n出入口（[门/通道的位置与样式]），地面（[地面材质与状态]），墙面（[墙面材质与颜色]），\n[主要陈设及其固定相对位置]，\n空间结构连续、自洽，\n[光源 + 色温 + 明暗对比]，[氛围]，\n画面中没有任何人物，空场景，电影质感\n```\n\n## 空间结构规则\n\n空间必须**读得懂、对得上、可复用**：\n\n- **前景**：框景/遮挡物（门框、桌角、植物、设备边缘），制造纵深——写出 1-2 个具体元素\n- **中景**：场景的主体空间与核心陈设（流水线、床铺、柜台）\n- **后景**：空间的延伸（远处的墙、窗、走廊、城市轮廓）\n- **出入口**：门、楼梯、通道的位置与样式必须明确（如\"画面左侧一扇铁门\"），这是后续镜头调度人物进出的依据\n- **地面与墙面**：材质、颜色、状态具体化（如\"水泥地面有油渍\"\"墙面石灰斑驳\"）\n- **主要陈设**：写出 2-4 个核心陈设及它们的**固定相对位置**（如\"流水线沿墙排开，尽头是吧台\"），陈设之间的左右/远近关系要自洽，不要只罗列物品名\n\n## 人物（硬性规则 · 最高优先级）\n\n**场景图中不能出现任何的人，只保留场景本身。**\n\n- 提示词中不描述人物、不提及任何与人物相关的内容\n- 场景描述（prompt）中出现的人物信息一律忽略，不写入提示词\n- 提示词结尾必须包含：\"画面中没有任何人物，空场景\"\n\n`prompt`（场景描述）中的陈设、年代质感、关键视觉元素必须全部落地；`lighting`（场景光影）要具体化：光源方向、色温冷暖、明暗对比（如\"头顶灯管发出冷白光，机器下方投下硬阴影\"）。\n\n## 视角与氛围\n\n- 稳定的平视或微俯广角，不要极端俯仰、鱼眼、倾斜构图（要作为固定场景反复复用）\n- 以 `location` + `time` 确定时间段与光线基调（日/夜/黄昏的光完全不同）\n- 氛围词具体化：\"压抑\" → \"空气闷热、光线昏暗低沉\"，不要只写抽象情绪词\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇\n\n## 禁止事项\n\n- 任何人物——**场景图中不能出现任何的人，只保留场景本身**\n- 文字、招牌上的可读文字、水印、签名\n- 动态模糊、运动中的物体（场景参考图必须静止稳定）\n- 只罗列陈设清单而不交代相对位置（空间结构必须连续、自洽）\n\n## 保存\n\n调用 `save_scene_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","backend/workspace/skills/extractor/SKILL.md":"---\nname: extractor\ndescription: 角色、场景和道具提取的规范与方法\n---\n\n# 角色、场景与道具提取指南\n\n## 角色提取规范\n\n提取的角色字段（与 `save_dedup_characters` 工具参数一一对应）：\n- **name**（必填）：角色全名\n- **role**：角色定位，主角/配角/龙套\n- **appearance**：样貌描写（300-500字）——性别、年龄感、五官、体态、气质。**角色的性格特点不要单独输出，要转化为外在气质与神态融入样貌描写**（例如\"性格冷峻\"应写为\"眼神冷峻、表情克制、少有笑意\"）\n- **styling**：妆造——发型、服装、妆面、配饰等\n- **description**：背景故事和人物关系（可选补充）\n\n## 场景提取规范\n\n提取的场景字段（与 `save_dedup_scenes` 工具参数一一对应）：\n- **location**（必填）：具体场所名称\n- **time**：时间段（如 白天/黄昏/深夜），同地点不同时段视为新场景\n- **prompt**：场景描述——空间、陈设、年代质感、关键视觉元素（纯背景，不含人物）\n- **lighting**：场景光影——光源、色调、明暗、氛围\n\n## 道具提取规范\n\n**核心原则：宁可少提，不要多提。** 道具是用来生成白底单品图、供视频特写引用的高成本资产，只有剧情关键道具才值得提取。一集通常 **0-3 个**关键道具，超过 3 个时按剧情重要性排序只保留前 3 个。\n\n必须**同时满足**以下两条，缺一不可：\n1. **直接推动剧情**：该物品的出现、交接、损坏或发现会引发情节转折（如凶器、信物、关键文件、定情礼物、关键证据）。\n2. **值得单独生成图片**：后续分镜会给它特写镜头或反复出现，需要固定外观。\n\n**判定三问**（对每个候选道具自问自答，任一答\"否\"即放弃）：\n- ① 删掉它剧情是否依然成立？→ 成立则**不提取**（它只是道具式背景板）\n- ② 它只是角色随手使用的日常物品吗（手机、筷子、水杯、香烟、雨伞）？→ 是则**不提取**\n- ③ 它是场景陈设的一部分吗（桌椅、灯具、门窗、挂画、餐具）？→ 是则**不提取**（这些属于场景描述）\n\n**不算道具的典型**：随手使用但不影响剧情走向的普通物品；场景陈设与家具；只被提及一次且再无下文的物品；角色的常规穿戴（归入角色妆造）。\n\n如果没有符合条件的道具，**不要强行提取**，调用 `save_dedup_props` 时传空数组即可。\n\n提取的道具字段（与 `save_dedup_props` 工具参数一一对应）：\n- **name**（必填）：道具名\n- **type**：类型——日常/武器/交通/装饰/文件等\n- **description**：物品外貌——只描写物品本身的物理外观（材质、颜色、形状、大小、新旧程度、磨损痕迹等），不要写剧情用途，不要涉及与角色或其他事物的关联\n\n道具**不需要输出图片提示词**——道具的最终提示词由提示词生成 Agent 在生图前专门生成（白底单品规范）。\n\n## 使用步骤\n\n1. 调用 `read_script_for_extraction` 读取当前集剧本\n2. 调用 `read_existing_characters` 查看项目已有角色和当前集已关联角色\n3. 调用 `read_existing_scenes` 查看项目已有场景和当前集已关联场景\n4. 调用 `read_existing_props` 查看项目已有道具和当前集已关联道具\n5. 只提取当前集真实涉及的角色、场景和道具\n6. 调用 `save_dedup_characters` 保存角色并自动关联到当前集\n7. 调用 `save_dedup_scenes` 保存场景并自动关联到当前集\n8. 调用 `save_dedup_props` 保存道具并自动关联到当前集\n\n## 当前集规则\n\n- 目标是补齐\"当前集\"需要的角色、场景和道具，不是重扫整个项目\n- 若已在项目中存在但当前集未关联，仍应复用并关联到当前集\n- 去重规则：角色/道具按名称精确匹配，场景按【地点+时间段】精确匹配，命中的优先复用，不要重复创建\n- 近名去重：名称带括号定位或别名时按括号前主体比较（如「林小雨（主角）」与「林小雨」视为同一角色/道具，复用已有）；read_existing_characters / read_existing_props 返回的 normalized_name 即归一化后的名字，场景的 normalized_location 同理，据此判断即可\n","backend/workspace/skills/storyboard-breaker/SKILL.md":"---\nname: storyboard-breaker\ndescription: 分镜拆解专业规范 — 将剧本拆分为可承载多个子镜头的分镜段落\n---\n\n# 分镜拆解指南\n\n## 核心定义：分镜段落\n\n一个分镜 = 一个 **分镜段落**（segment）= 一个视频生成任务。\n\n- 每个段落时长 **8-15 秒**，内部承载 **2-4 个子镜头**\n- 子镜头之间**可以切镜**：换景别、换角度、换拍摄对象，用硬切衔接\n- 子镜头之间**不跨场景**：一个段落只发生在一个场景内（`scene_id` 是段落级绑定）\n- 每个子镜头 2-6 秒，聚焦一个画面单元（一个动作、一个反应、一个特写）\n\n## 拆分流程（四步）\n\n1. 调用 `read_storyboard_context` 读取剧本、角色、场景、道具、已有分镜摘要\n2. **节拍识别**：先识别剧本的叙事节拍——剧本中的【开场】【触发】【高潮】【收尾】等标记，或叙事转折点（地点转移、规则揭示、情绪爆发、反转）。**节拍边界强制切段**，同一节拍内的子镜头优先归入同一段落，不把一条因果链（铺垫-发生-反应）切散到不同段落\n3. **总量锚定**：目标总时长 = 剧本字数 ÷ 500字/分钟；段落数 ≈ 目标总时长 ÷ 12秒，允许 ±20% 浮动。不要明显超出或不足\n4. **段落内拆子镜头**：按动作切换点、视角切换点、对象切换点切分子镜头，为每个段落补全完整字段后调用 `save_storyboards` 一次性保存\n\n## 节奏分层时长\n\n按段落功能确定时长，不要一刀切：\n\n| 段落类型 | 时长 | 说明 |\n|---|---|---|\n| 过渡段 | 8-10 秒 | 赶路、空镜、环境建立、转场 |\n| 叙事段 | 10-15 秒 | 常规剧情推进、对话 |\n| 爆点段 | 12-15 秒 | 特写、规则揭示、情感爆发、反转；子镜头节奏放慢，单个子镜头可停留 4-6 秒 |\n\n## 台词时长下限（硬规则）\n\n**段落时长 ≥ 段内台词与旁白总字数（写在 description 中的部分）÷ 4.5字/秒 + 2秒表演余量**\n\n装不下的台词必须拆到下一个段落，不允许把演不完的台词塞进一个段落。\n\n## 镜头要素\n\n1. **镜头标题**：3-5字概括段落核心内容（如\"噩梦惊醒\"）\n2. **时间**：具体时分 + 光线描述\n3. **地点**：场景完整描述 + 空间布局 + 环境细节\n4. **景别**：段落内主导景别；多景别段落写组合，如\"中景+特写\"\n5. **角度**：平视/仰视/俯视/侧面/背面\n6. **运镜**：固定/推镜/拉镜/摇镜/跟镜/移镜（段落内不同子镜头可不同）\n7. **画面描述** `description`：按 `【镜头1】…【镜头2】…` 逐子镜头描述观众实际看到和听到的内容——画面（谁 + 具体动作 + 肢体细节 + 表情）写在前；该子镜头有台词时以「角色名说：「台词」」写在对应 `【镜头N】` 内，旁白写「旁白：内容」\n8. **画面结果** `result`：段落结尾的即时后果 + 视觉细节\n9. **氛围** `atmosphere`：光线 + 色调 + 声音 + 整体氛围\n10. **时长** `duration`：段落总时长 8-15 秒，且满足台词时长下限\n11. **场景关联**：若能匹配已有场景，必须填写 `scene_id`\n12. **角色关联**：填写 `character_ids`，绑定当前段落涉及的 0 到多个角色\n13. **道具关联**：填写 `prop_ids`，绑定当前段落出现的关键道具（0 到多个）\n\n## 场景关联规则\n\n- 优先使用 `read_storyboard_context` 返回的 `scenes`\n- `location + time` 可明确匹配时，必须回填正确 `scene_id`\n- 不要凭空生成不存在的场景 ID\n- 如果剧本内容明显落在已有场景中，不要重复创造新场景描述\n\n## 角色绑定规则\n\n- `character_ids` 必须从 `read_storyboard_context` 返回的角色列表中选择\n- 一个段落可以没有角色，也可以绑定多个角色\n- 只要段落里有明确出场、被看见、发生动作或说话的角色，都应绑定进去\n- 纯环境段落、空镜、物件特写可以传空数组\n\n## 道具绑定规则\n\n- `prop_ids` 必须从 `read_storyboard_context` 返回的道具列表（`props`）中选择\n- 道具被角色使用、交接、特写，或在画面中明显可见且对叙事有意义时，必须绑定到该段落\n- 道具特写段落（无角色）也应绑定道具，`character_ids` 可为空\n- 与剧情无关的背景物品、场景陈设不要绑定；没有道具出现的段落传空数组\n- 绑定的道具会作为视频生成的参考图（白底单品图），保证道具外观跨段落一致\n\n## 质量要求\n\n- `description` 要适合人读，按子镜头详细描述观众实际看到和听到的内容；台词/旁白直接写在对应 `【镜头N】` 内\n- `image_prompt` 要突出单帧构图、角色外观、环境和光线（对应段落第一个子镜头）\n- `bgm_prompt` 和 `sound_effect` 用简洁短语即可，但不能空泛到只有“紧张”“悲伤”\n- 如需调整，调用 `update_storyboard` 修改具体段落\n","CLAUDE.md":"# CLAUDE.md\n\n## Project Overview\n\n火宝短剧（Huobao Drama）— AI 短剧/漫剧一站式制作工具。全 TypeScript 栈：小说 → 剧本改写 → 资产提取 → 生图 → 分镜拆解 → 生视频 → FFmpeg 拼接导出。支持 Electron 桌面版（macOS dmg）与服务器部署。\n\n## Structure\n\n```\nbackend/   — Hono + Drizzle ORM (better-sqlite3) + Mastra (AI agents)\nbackend/workspace/ — Agent 工作目录（Mastra Workspace jail 根）\nbackend/workspace/skills/ — Agent SKILL.md definitions（设置页可在线编辑）\nfrontend/  — Nuxt 3 + Vue 3 + TypeScript，ssr:false（纯 CSS，无 UI 框架）\ndesktop/   — Electron 桌面版：主进程 + esbuild 打包脚本 + electron-builder 配置\ndata/      — SQLite 数据库（huobao.sqlite3）+ 生成的静态文件（static/）\nconfigs/   — 遗留死配置，代码零引用\n```\n\n## Commands\n\n### Backend (`backend/`)\n- `npm run dev` — tsx watch 开发服务（端口 5679）\n- `npm start` — tsx 生产启动\n- `npm run typecheck` — TypeScript 类型检查\n- `npm run backfill-artwork` — 存量图片/视频补缩略图与海报帧\n\n### Frontend (`frontend/`)\n- `npm run dev` — Vite 开发服务（端口 3013，代理 /api 与 /static 到 5679）\n- `npm run generate` — 产出含 index.html 的静态站点（`.output/public`；`nuxt build` 不产 index.html，不能用于静态托管）\n\n### Desktop (`desktop/`，根目录 `npm run dist` 串联全流程)\n- `npm run dev` — 打包后端 bundle + Electron 窗口运行\n- `npm run build:backend` — esbuild 打包 backend/src → build/backend.mjs（ESM；externals: sharp/better-sqlite3/ffmpeg-static/ffprobe-static）\n- `npm run build:main` — 打包主进程 → dist/main.js\n- `npm run rebuild:native` — better-sqlite3 按 Electron ABI 重编（原生模块 ABI 变化后必须执行；postinstall 已自动做）\n- `npm run dist` — prepare-resources + electron-builder 出 arm64/x64 dmg → release/\n- `npm run dist:win` — 交叉打包 Windows NSIS 安装器（win-x64）；win 版 ffmpeg.exe 缓存在 build/win-bin/（缺失时脚本提示下载地址）\n\n## Architecture\n\n### Backend\n- **HTTP**: Hono（入口 `src/index.ts`），路由挂 `/api/v1`，`/static` 服务 DATA_ROOT，生产托管前端静态目录\n- **Database**: SQLite（better-sqlite3 + WAL），`SQLITE_PATH` 覆盖库文件位置；DDL 在 `src/db/sqlite-schema.ts`，启动时幂等重放；Drizzle 表定义 `src/db/schema.ts`（sqlite-core）\n- **路径锚点**: `src/utils/paths.ts` 统一解析 DATA_ROOT/STORAGE_ROOT；桌面版由 Electron 主进程注入 env（`HUOBAO_DATA_DIR`/`SQLITE_PATH`/`WORKSPACE_PATH`/`FRONTEND_DIST`/`FFMPEG_BIN`/`FFPROBE_BIN`），dev 走仓库相对路径默认值\n- **AI Agents**: Mastra，4 个 agent（script_rewriter / extractor / storyboard_breaker / prompt_generator），instructions 从 `workspace/prompts/*.md` + skills 动态拼接，模型按请求解析；fetch 补丁链适配国内中转站（关思考/温度/max_tokens）\n- **媒体生成**: `services/generation.ts` 统一任务生命周期（sys_task 表），适配器模式：图片 openai/gemini/volcengine，视频 volcengine/minimax\n- **视频拼接**: `services/ffmpeg-merge.ts`，FFmpeg 二进制内置（ffmpeg-static），可用 `FFMPEG_BIN`/`FFPROBE_BIN` 覆盖\n\n### Frontend\n- Nuxt 3 SPA，动态路由在 `nuxt.config.ts` 的 `pages:extend` 手动注册（views/drama/）\n- `app/composables/useApi.ts` 统一 fetch 客户端（全相对路径，生产与后端同源）\n- 核心工作台 `app/views/drama/episode.vue`（剧本→制作→导出流水线）\n\n### Desktop\n- 主进程 `desktop/src/main.ts`：单实例锁 → 空闲端口 → userData 准备（workspace 模板 copy-once + `.template-version` 版本标记）→ `utilityProcess.fork` 后端 → 轮询 health → BrowserWindow\n- userData：打包版 `~/Library/Application Support/HuobaoDrama/`，dev 版 `HuobaoDrama-Dev/`（互不干扰）\n- 后端 bundle 在 asar 内（externals 经 asar node_modules 解析，.node 自动重定向 unpacked）\n\n## Database\nSQLite 单文件（默认 `data/huobao.sqlite3`，桌面版在 userData）。启动时 `initSqliteSchema` 幂等建表 + 风格预设种子。MySQL→SQLite 一次性迁移：`cd backend && npx tsx scripts/import-mysql-to-sqlite.ts [--force]`（逐表行数校验、写前备份）。\n\n## Key Config\n- AI 服务配置存 DB（`ai_service_configs` 表），设置页维护，不在配置文件\n- 环境变量全集见 README「环境变量」；`configs/config.yaml` 是死配置（勿参考）\n- `PUBLIC_BASE_URL`：Seedance 引用本地参考资源需公网地址，桌面版无此能力（有中文报错）\n"},"files":{"backend/workspace/skills/prompt-generator/video-prompt/SKILL.md":"---\nname: video-prompt\ndescription: 视频提示词规范 — 根据分镜段落内容生成按时间分段、段内可切镜的视频生成提示词\n---\n\n# 视频提示词（分镜段落 → video_prompt）\n\n根据单个分镜段落的 description（含【镜头N】子镜头结构与台词/旁白）/ atmosphere / duration，生成驱动 AI 视频生成的 `video_prompt`。**一个分镜段落 = 一段 8-15 秒的视频，内部允许切镜**：段与段之间可以是不同镜头（换景别/角度/对象），用硬切衔接；但**全程不跨场景**、不闪回。\n\n## 格式\n\n`video_prompt` 的**第一行是信息头**：先介绍这条视频有哪些人物和场景，然后再接时间分段。人物、场景一律用 @ 引用（生成时会替换为对应参考图片标记，让视频模型先对上\"谁\"和\"在哪\"）。\n\n```\n出场人物：@小明、@小红；场景：@咖啡厅。\n0-3秒：@咖啡厅，近景固定镜头，@小明低头看手机，手指反复敲桌面，表情焦虑。\n3-6秒：切到门口全景，门铃响，@小红推门走入，带进一阵冷风。\n6-9秒：切回中景，@小红微笑着走向小明坐下，小明说：「你终于来了。」\n```\n\n信息头规则：\n- 只列该分镜段落实际出场的人物和绑定的场景，不要列没出场的\n- 有明显道具出场时可在信息头追加（如 `；道具：@信件`）\n- 信息头独立一行，以句号结尾，之后是时间分段\n\n按 3 秒为一段，每段单独一行、用换行分隔，时间范围连续衔接（无重叠、无空缺）。\n\n## 与分镜描述的映射\n\n`description` 是 video_prompt 的唯一内容来源（画面、动作、台词、旁白都在其中），转换规则：\n\n- `description` 的每个 `【镜头N】` 映射为 **1-2 个连续的 3 秒段**，顺序一致、不遗漏、不合并、不新增子镜头\n- 台词/旁白从对应 `【镜头N】` 内的「角色名说：「…」」「旁白：…」提取，分配到该子镜头映射的段；**不要创作 description 之外的新台词**\n- 画面动作以 `description` 为准；`atmosphere` 只用于补各段的光线、色调与氛围描写\n\n## 段内结构\n\n每一段按此顺序组织内容（可省略无内容的项，但动作/画面必须有）：\n\n**时间范围 ＋ 场景@引用 ＋ 景别/运镜 ＋ 角色@引用＋主体动作·表情 ＋ 对白/旁白 ＋ 氛围光线**\n\n- **第一段必须建立空间**：场景 + 机位 + 角色的位置与状态，让观众一眼知道在哪、看谁\n- **切镜**：切镜后的段开头用\"切到/切回\"等衔接词，并重新交代景别与主体；切镜点应对齐分镜 `description` 中的 `【镜头N】` 结构\n- **景别/运镜**：每段一个镜头状态（近景/中景/全景/特写；固定/推/拉/摇/跟）；单个子镜头内运镜连续，切镜后可更换运镜方式\n- **动作**：每段一个主动作，动词具体可见（走、转身、抬头、攥紧、停顿）\n- **情绪全部转为可见描写**：不要\"他很伤心/气氛紧张\"这类抽象词，写成\"他低下头、手指攥紧杯沿、呼吸变重\"\n- **对白/旁白**：写「角色名说：「台词」」，旁白写「旁白：内容」；3 秒念不完的长台词拆到多段；无对白的段可写环境音/动作音（如\"机器持续轰鸣\"）\n\n## 引用规则\n\n- `@场景名` — 场景引用，名字必须与场景列表中的地点完全一致\n- `@角色名` — 角色引用，名字必须与角色列表中的名字完全一致\n- `@道具名` — 道具引用，名字必须与道具列表中的名字完全一致；道具在画面中明显可见、被使用或特写时引用\n- 生成时会自动把 `@名字` 替换为对应参考图片标记（如 `@小明` → `@图片1小明`），因此名字必须精确匹配，不要缩写或加额外符号\n- **每段至少一个 @ 引用锚定画面**；角色出场的段必须 @ 该角色；只引用该分镜段落已绑定的场景/角色/道具\n\n## 时间轴规则\n\n- 段数 = 分镜段落 duration ÷ 3 秒（向上取整），各段时间范围相加必须等于段落总时长\n- 内容节奏：第一段建立 → 中段推进动作/冲突 → 末段落到结果或情绪点\n\n## 禁止事项\n\n- 跨场景切换、闪回（一个段落只发生在一个场景内）\n- 引用列表之外的场景/角色名\n- 抽象心理描写、文学化比喻（模型只认可见画面）\n- 语言与会话语言指令不符\n\n## 保存\n\n调用 `update_storyboard` 仅更新该分镜段落的 `video_prompt` 字段，不要改动其他字段，不要重新拆分整集。\n","backend/workspace/skills/script-rewriter/SKILL.md":"---\nname: script-rewriter\ndescription: 小说改写为格式化剧本的方法论和规范\n---\n\n# 剧本改写指南\n\n## 改写原则\n\n1. **保留核心情节**：不改变主线故事和角色关系\n2. **增强画面感**：将叙述性文字转化为可视化的场景描写\n3. **对话驱动**：用对白推动情节，减少旁白\n4. **节奏把控**：每场戏控制在 30-60 秒，适合短视频\n5. **不写镜头语言**：不涉及景别、角度、运镜，这些属于分镜拆解步骤\n\n## 格式化剧本格式\n\n```\n## S01 | 内景 · 咖啡厅 | 黄昏\n\n黄昏的光线透过落地窗洒进咖啡厅，吧台上咖啡杯热气升腾。\n\n小明独自坐在角落卡座，低头看手机，神情有些焦虑。\n\n门铃响起，小红推门而入。她看到小明，微笑着走过去。\n\n小红：（微笑）等很久了吗？\n小明：（抬头）还好，刚到。\n```\n\n### 格式规则\n\n- `## S编号 | 内景/外景 · 地点 | 时间段` — 场景头\n- 动作描写自然段 — 不包含任何镜头语言\n- `角色名：（状态/表情）台词内容` — 对白格式\n\n### 内容量参考\n\n格式化剧本相比原始内容增加约 20-30%，主要增量是场景头标记和对白格式化，不是扩写。\n\n## 改写步骤\n\n1. 先调用 `read_episode_script` 读取原始内容\n2. 分析内容结构（对话、叙述、心理描写的比例）\n3. 调用 `rewrite_to_screenplay` 执行改写\n4. 检查改写结果，确认符合格式化剧本格式\n5. 调用 `save_script` 保存最终结果\n\n## 注意事项\n\n- 心理描写可转化为角色表情/动作或画外音\n- 长段叙述拆分为多个短场景\n- 确保每个场景有明确的情绪转折点\n- 保持角色语言风格一致性\n- 场景编号连续递增（S01, S02, S03...）\n- 时间段要具体（黄昏、深夜、清晨），不要笼统写\"白天\"\n","backend/workspace/skills/prompt-generator/prop-prompt/SKILL.md":"---\nname: prop-prompt\ndescription: 道具最终提示词规范 — 白底单品静物，标准产品摄影视角：比例准确、边缘完整、背景不承载叙事\n---\n\n# 道具最终提示词（白底单品 · 标准产品摄影）\n\n生成的是一张白底单品图（product shot）：**采用标准产品摄影视角**，画面中只有道具本身，孤立放置在纯白背景上，**不掺杂任何其他元素**——没有其他物品、没有人物、没有场景环境、没有手部持握。\n\n三条硬性要求：\n1. **物品各部分比例准确**——不要夸张、变形或风格化拉伸，道具的相对尺寸关系必须真实\n2. **边缘完整**——道具整体完整入镜，四周留白，任何部分都不得被画面边缘裁切\n3. **背景不承载任何叙事内容**——纯白背景只是衬底，不带场景感、不带情节暗示、不带装饰元素\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n单品产品图，标准产品摄影视角，[道具名 + 材质/颜色/形状/大小 + 新旧程度与磨损细节]，\n物品各部分比例准确，孤立放置在纯白背景上，居中完整入镜，边缘完整无裁切，\n背景纯净不承载任何叙事内容，无其他物品、无人物、无场景，\n柔和均匀的影棚光，轻淡阴影，高细节\n```\n\n## 生成规则\n\n- 以道具 `name`（名称）与 `description`（物品外貌）为核心：材质、颜色、形状、大小、新旧程度、磨损痕迹等物理细节**逐项落地**，这是道具辨识度的来源\n- 标准产品摄影视角：微俯视 3/4 视角（同时看清顶面与侧面，最有立体感）；扁平道具（纸张、证件、照片）用正俯视平铺\n- 单品居中完整呈现，四周留白，比例准确、边缘完整，不要裁切道具主体\n- 柔和均匀的影棚光，阴影轻淡，高细节\n- 只描写物品本身，不要提及剧情、角色或用途（背景与画面都不承载叙事内容）\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇；**不要**\"电影质感\"类词汇（道具图是产品图不是剧照）\n\n## 禁止事项\n\n- 手部持握、人物、其他物品、场景环境入镜\n- 包装、底座、展示架（除非它就是道具本体的一部分）\n- 文字、水印、签名（道具本体上印刷的文字图案可以保留并描述）\n- 环境反光、彩色光\n- 夸张透视、变形、比例失真、边缘裁切\n\n## 保存\n\n调用 `save_prop_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","backend/workspace/skills/prompt-generator/character-prompt/SKILL.md":"---\nname: character-prompt\ndescription: 角色最终提示词规范 — 正脸特写 + 三视图（character turnaround：正面/90 度侧面/背面），作为后续所有生成的形象锚点\n---\n\n# 角色最终提示词（左侧正脸特写 + 右侧三视图）\n\n生成的是一张角色设定参考图（character reference sheet），构图固定为：\n\n- **左侧：正脸特写**——头部与肩部的正面近景，五官、发型、肤质清晰可见，作为脸部辨识度的锚点\n- **右侧：并列展示正面、90 度侧面、背面三张等高全身视图**——同一角色的三个全身视图等高并排，头顶与脚底对齐\n\n**核心原则：一致性 > 美观。** 这张图是后续所有角色图片、视频参考的形象锚点，必须中性、清晰、可复用——不要追求单张图的艺术感。\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n角色设定参考图，左侧为正脸特写，右侧并列展示正面、90 度侧面、背面三张等高全身视图，\n特写与全身视图都是同一角色，全身入镜，中性 A 字站姿，三张全身视图等高并排、头顶脚底对齐，\n[年龄感 + 性别感 + 体态]，[五官特征]，[发型]，[服装 + 配饰]，\n正脸特写与三个视图的脸、发型和服装完全一致，\n纯白背景，柔和均匀的光线，电影质感\n```\n\n## 描述顺序规则\n\n把**最有辨识度的特征放在前面**，按此顺序落地 `appearance`（样貌）与 `styling`（妆造）的每个关键元素，不遗漏：\n\n1. 身份锚点：年龄感（如\"二十出头\"）、性别感、体态（高矮胖瘦、姿态习惯）\n2. 五官：脸型、眼睛、其他显著特征（疤、痣、眼镜等）——正脸特写尤其依赖这部分描写\n3. 发型：颜色、长度、样式\n4. 服装：款式、颜色、材质、状态（如\"袖口有焊锡痕迹的皱褶工服\"）\n5. 配饰：只写有辨识度的，不堆砌\n\n角色的性格特点要转化为外在气质与神态描写（如\"憔悴\" → \"眼神疲惫、肩膀微垮\"），不要直接出现性格词汇。\n\n## 构图与一致性\n\n- 左侧正脸特写：正面朝向镜头、中性表情、头顶到肩膀完整入镜\n- 右侧三张全身视图：同一角色的正面、90 度侧面、背面，**等高并排、间距均匀**，头顶与脚底在同一水平线上\n- 特写与三张全身视图必须是同一张脸、同一发型、同一服装——明确写出\"正脸特写与三张全身视图的脸、发型和服装完全一致\"\n- 中性站姿、自然表情——方便作为参考图复用\n- 柔和均匀的棚拍光，不要戏剧性光影（参考图要在各种场景下都能用）\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇\n\n## 禁止事项\n\n- 动态姿势、夸张表情、手持道具、与他人同框\n- 裁切身体（全身视图必须 full body，头顶到脚底完整入镜；特写必须头部肩部完整入镜）\n- 文字、标签、水印、签名\n- 重阴影、彩色背景光、背景道具\n\n## 保存\n\n调用 `save_character_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","backend/workspace/skills/prompt-generator/scene-prompt/SKILL.md":"---\nname: scene-prompt\ndescription: 场景最终提示词规范 — 清晰广角建立镜头：前景/中景/后景/出入口/地面/墙面/主要陈设的固定相对位置，空间连续自洽可复用，无人物\n---\n\n# 场景最终提示词（广角建立镜头 · 无人物空镜）\n\n生成的是一张**清晰的广角建立镜头（establishing shot）**场景图：**完全没有人物**的纯场景空镜，完整展示**前景、中景、后景、出入口、地面、墙面及主要陈设的固定相对位置**，空间结构连续、自洽且可复用。\n\n这张图会作为该场景所有镜头的背景参考锚点：观众和模型都必须能从这张图读懂整个空间的布局——从哪里进出、地面与墙面是什么质感、核心陈设各自固定在什么位置。视角必须稳定、通用。\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n固定机位广角镜头，清晰的建立镜头，[地点 + 年代质感]，[时间段]，\n前景（[前景元素]）、中景（[中景主体空间]）、后景（[后景纵深]）三层分层构图，\n出入口（[门/通道的位置与样式]），地面（[地面材质与状态]），墙面（[墙面材质与颜色]），\n[主要陈设及其固定相对位置]，\n空间结构连续、自洽，\n[光源 + 色温 + 明暗对比]，[氛围]，\n画面中没有任何人物，空场景，电影质感\n```\n\n## 空间结构规则\n\n空间必须**读得懂、对得上、可复用**：\n\n- **前景**：框景/遮挡物（门框、桌角、植物、设备边缘），制造纵深——写出 1-2 个具体元素\n- **中景**：场景的主体空间与核心陈设（流水线、床铺、柜台）\n- **后景**：空间的延伸（远处的墙、窗、走廊、城市轮廓）\n- **出入口**：门、楼梯、通道的位置与样式必须明确（如\"画面左侧一扇铁门\"），这是后续镜头调度人物进出的依据\n- **地面与墙面**：材质、颜色、状态具体化（如\"水泥地面有油渍\"\"墙面石灰斑驳\"）\n- **主要陈设**：写出 2-4 个核心陈设及它们的**固定相对位置**（如\"流水线沿墙排开，尽头是吧台\"），陈设之间的左右/远近关系要自洽，不要只罗列物品名\n\n## 人物（硬性规则 · 最高优先级）\n\n**场景图中不能出现任何的人，只保留场景本身。**\n\n- 提示词中不描述人物、不提及任何与人物相关的内容\n- 场景描述（prompt）中出现的人物信息一律忽略，不写入提示词\n- 提示词结尾必须包含：\"画面中没有任何人物，空场景\"\n\n`prompt`（场景描述）中的陈设、年代质感、关键视觉元素必须全部落地；`lighting`（场景光影）要具体化：光源方向、色温冷暖、明暗对比（如\"头顶灯管发出冷白光，机器下方投下硬阴影\"）。\n\n## 视角与氛围\n\n- 稳定的平视或微俯广角，不要极端俯仰、鱼眼、倾斜构图（要作为固定场景反复复用）\n- 以 `location` + `time` 确定时间段与光线基调（日/夜/黄昏的光完全不同）\n- 氛围词具体化：\"压抑\" → \"空气闷热、光线昏暗低沉\"，不要只写抽象情绪词\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇\n\n## 禁止事项\n\n- 任何人物——**场景图中不能出现任何的人，只保留场景本身**\n- 文字、招牌上的可读文字、水印、签名\n- 动态模糊、运动中的物体（场景参考图必须静止稳定）\n- 只罗列陈设清单而不交代相对位置（空间结构必须连续、自洽）\n\n## 保存\n\n调用 `save_scene_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","backend/workspace/skills/extractor/SKILL.md":"---\nname: extractor\ndescription: 角色、场景和道具提取的规范与方法\n---\n\n# 角色、场景与道具提取指南\n\n## 角色提取规范\n\n提取的角色字段（与 `save_dedup_characters` 工具参数一一对应）：\n- **name**（必填）：角色全名\n- **role**：角色定位，主角/配角/龙套\n- **appearance**：样貌描写（300-500字）——性别、年龄感、五官、体态、气质。**角色的性格特点不要单独输出，要转化为外在气质与神态融入样貌描写**（例如\"性格冷峻\"应写为\"眼神冷峻、表情克制、少有笑意\"）\n- **styling**：妆造——发型、服装、妆面、配饰等\n- **description**：背景故事和人物关系（可选补充）\n\n## 场景提取规范\n\n提取的场景字段（与 `save_dedup_scenes` 工具参数一一对应）：\n- **location**（必填）：具体场所名称\n- **time**：时间段（如 白天/黄昏/深夜），同地点不同时段视为新场景\n- **prompt**：场景描述——空间、陈设、年代质感、关键视觉元素（纯背景，不含人物）\n- **lighting**：场景光影——光源、色调、明暗、氛围\n\n## 道具提取规范\n\n**核心原则：宁可少提，不要多提。** 道具是用来生成白底单品图、供视频特写引用的高成本资产，只有剧情关键道具才值得提取。一集通常 **0-3 个**关键道具，超过 3 个时按剧情重要性排序只保留前 3 个。\n\n必须**同时满足**以下两条，缺一不可：\n1. **直接推动剧情**：该物品的出现、交接、损坏或发现会引发情节转折（如凶器、信物、关键文件、定情礼物、关键证据）。\n2. **值得单独生成图片**：后续分镜会给它特写镜头或反复出现，需要固定外观。\n\n**判定三问**（对每个候选道具自问自答，任一答\"否\"即放弃）：\n- ① 删掉它剧情是否依然成立？→ 成立则**不提取**（它只是道具式背景板）\n- ② 它只是角色随手使用的日常物品吗（手机、筷子、水杯、香烟、雨伞）？→ 是则**不提取**\n- ③ 它是场景陈设的一部分吗（桌椅、灯具、门窗、挂画、餐具）？→ 是则**不提取**（这些属于场景描述）\n\n**不算道具的典型**：随手使用但不影响剧情走向的普通物品；场景陈设与家具；只被提及一次且再无下文的物品；角色的常规穿戴（归入角色妆造）。\n\n如果没有符合条件的道具，**不要强行提取**，调用 `save_dedup_props` 时传空数组即可。\n\n提取的道具字段（与 `save_dedup_props` 工具参数一一对应）：\n- **name**（必填）：道具名\n- **type**：类型——日常/武器/交通/装饰/文件等\n- **description**：物品外貌——只描写物品本身的物理外观（材质、颜色、形状、大小、新旧程度、磨损痕迹等），不要写剧情用途，不要涉及与角色或其他事物的关联\n\n道具**不需要输出图片提示词**——道具的最终提示词由提示词生成 Agent 在生图前专门生成（白底单品规范）。\n\n## 使用步骤\n\n1. 调用 `read_script_for_extraction` 读取当前集剧本\n2. 调用 `read_existing_characters` 查看项目已有角色和当前集已关联角色\n3. 调用 `read_existing_scenes` 查看项目已有场景和当前集已关联场景\n4. 调用 `read_existing_props` 查看项目已有道具和当前集已关联道具\n5. 只提取当前集真实涉及的角色、场景和道具\n6. 调用 `save_dedup_characters` 保存角色并自动关联到当前集\n7. 调用 `save_dedup_scenes` 保存场景并自动关联到当前集\n8. 调用 `save_dedup_props` 保存道具并自动关联到当前集\n\n## 当前集规则\n\n- 目标是补齐\"当前集\"需要的角色、场景和道具，不是重扫整个项目\n- 若已在项目中存在但当前集未关联，仍应复用并关联到当前集\n- 去重规则：角色/道具按名称精确匹配，场景按【地点+时间段】精确匹配，命中的优先复用，不要重复创建\n- 近名去重：名称带括号定位或别名时按括号前主体比较（如「林小雨（主角）」与「林小雨」视为同一角色/道具，复用已有）；read_existing_characters / read_existing_props 返回的 normalized_name 即归一化后的名字，场景的 normalized_location 同理，据此判断即可\n","backend/workspace/skills/storyboard-breaker/SKILL.md":"---\nname: storyboard-breaker\ndescription: 分镜拆解专业规范 — 将剧本拆分为可承载多个子镜头的分镜段落\n---\n\n# 分镜拆解指南\n\n## 核心定义：分镜段落\n\n一个分镜 = 一个 **分镜段落**（segment）= 一个视频生成任务。\n\n- 每个段落时长 **8-15 秒**，内部承载 **2-4 个子镜头**\n- 子镜头之间**可以切镜**：换景别、换角度、换拍摄对象，用硬切衔接\n- 子镜头之间**不跨场景**：一个段落只发生在一个场景内（`scene_id` 是段落级绑定）\n- 每个子镜头 2-6 秒，聚焦一个画面单元（一个动作、一个反应、一个特写）\n\n## 拆分流程（四步）\n\n1. 调用 `read_storyboard_context` 读取剧本、角色、场景、道具、已有分镜摘要\n2. **节拍识别**：先识别剧本的叙事节拍——剧本中的【开场】【触发】【高潮】【收尾】等标记，或叙事转折点（地点转移、规则揭示、情绪爆发、反转）。**节拍边界强制切段**，同一节拍内的子镜头优先归入同一段落，不把一条因果链（铺垫-发生-反应）切散到不同段落\n3. **总量锚定**：目标总时长 = 剧本字数 ÷ 500字/分钟；段落数 ≈ 目标总时长 ÷ 12秒，允许 ±20% 浮动。不要明显超出或不足\n4. **段落内拆子镜头**：按动作切换点、视角切换点、对象切换点切分子镜头，为每个段落补全完整字段后调用 `save_storyboards` 一次性保存\n\n## 节奏分层时长\n\n按段落功能确定时长，不要一刀切：\n\n| 段落类型 | 时长 | 说明 |\n|---|---|---|\n| 过渡段 | 8-10 秒 | 赶路、空镜、环境建立、转场 |\n| 叙事段 | 10-15 秒 | 常规剧情推进、对话 |\n| 爆点段 | 12-15 秒 | 特写、规则揭示、情感爆发、反转；子镜头节奏放慢，单个子镜头可停留 4-6 秒 |\n\n## 台词时长下限（硬规则）\n\n**段落时长 ≥ 段内台词与旁白总字数（写在 description 中的部分）÷ 4.5字/秒 + 2秒表演余量**\n\n装不下的台词必须拆到下一个段落，不允许把演不完的台词塞进一个段落。\n\n## 镜头要素\n\n1. **镜头标题**：3-5字概括段落核心内容（如\"噩梦惊醒\"）\n2. **时间**：具体时分 + 光线描述\n3. **地点**：场景完整描述 + 空间布局 + 环境细节\n4. **景别**：段落内主导景别；多景别段落写组合，如\"中景+特写\"\n5. **角度**：平视/仰视/俯视/侧面/背面\n6. **运镜**：固定/推镜/拉镜/摇镜/跟镜/移镜（段落内不同子镜头可不同）\n7. **画面描述** `description`：按 `【镜头1】…【镜头2】…` 逐子镜头描述观众实际看到和听到的内容——画面（谁 + 具体动作 + 肢体细节 + 表情）写在前；该子镜头有台词时以「角色名说：「台词」」写在对应 `【镜头N】` 内，旁白写「旁白：内容」\n8. **画面结果** `result`：段落结尾的即时后果 + 视觉细节\n9. **氛围** `atmosphere`：光线 + 色调 + 声音 + 整体氛围\n10. **时长** `duration`：段落总时长 8-15 秒，且满足台词时长下限\n11. **场景关联**：若能匹配已有场景，必须填写 `scene_id`\n12. **角色关联**：填写 `character_ids`，绑定当前段落涉及的 0 到多个角色\n13. **道具关联**：填写 `prop_ids`，绑定当前段落出现的关键道具（0 到多个）\n\n## 场景关联规则\n\n- 优先使用 `read_storyboard_context` 返回的 `scenes`\n- `location + time` 可明确匹配时，必须回填正确 `scene_id`\n- 不要凭空生成不存在的场景 ID\n- 如果剧本内容明显落在已有场景中，不要重复创造新场景描述\n\n## 角色绑定规则\n\n- `character_ids` 必须从 `read_storyboard_context` 返回的角色列表中选择\n- 一个段落可以没有角色，也可以绑定多个角色\n- 只要段落里有明确出场、被看见、发生动作或说话的角色，都应绑定进去\n- 纯环境段落、空镜、物件特写可以传空数组\n\n## 道具绑定规则\n\n- `prop_ids` 必须从 `read_storyboard_context` 返回的道具列表（`props`）中选择\n- 道具被角色使用、交接、特写，或在画面中明显可见且对叙事有意义时，必须绑定到该段落\n- 道具特写段落（无角色）也应绑定道具，`character_ids` 可为空\n- 与剧情无关的背景物品、场景陈设不要绑定；没有道具出现的段落传空数组\n- 绑定的道具会作为视频生成的参考图（白底单品图），保证道具外观跨段落一致\n\n## 质量要求\n\n- `description` 要适合人读，按子镜头详细描述观众实际看到和听到的内容；台词/旁白直接写在对应 `【镜头N】` 内\n- `image_prompt` 要突出单帧构图、角色外观、环境和光线（对应段落第一个子镜头）\n- `bgm_prompt` 和 `sound_effect` 用简洁短语即可，但不能空泛到只有“紧张”“悲伤”\n- 如需调整，调用 `update_storyboard` 修改具体段落\n","CLAUDE.md":"# CLAUDE.md\n\n## Project Overview\n\n火宝短剧（Huobao Drama）— AI 短剧/漫剧一站式制作工具。全 TypeScript 栈：小说 → 剧本改写 → 资产提取 → 生图 → 分镜拆解 → 生视频 → FFmpeg 拼接导出。支持 Electron 桌面版（macOS dmg）与服务器部署。\n\n## Structure\n\n```\nbackend/   — Hono + Drizzle ORM (better-sqlite3) + Mastra (AI agents)\nbackend/workspace/ — Agent 工作目录（Mastra Workspace jail 根）\nbackend/workspace/skills/ — Agent SKILL.md definitions（设置页可在线编辑）\nfrontend/  — Nuxt 3 + Vue 3 + TypeScript，ssr:false（纯 CSS，无 UI 框架）\ndesktop/   — Electron 桌面版：主进程 + esbuild 打包脚本 + electron-builder 配置\ndata/      — SQLite 数据库（huobao.sqlite3）+ 生成的静态文件（static/）\nconfigs/   — 遗留死配置，代码零引用\n```\n\n## Commands\n\n### Backend (`backend/`)\n- `npm run dev` — tsx watch 开发服务（端口 5679）\n- `npm start` — tsx 生产启动\n- `npm run typecheck` — TypeScript 类型检查\n- `npm run backfill-artwork` — 存量图片/视频补缩略图与海报帧\n\n### Frontend (`frontend/`)\n- `npm run dev` — Vite 开发服务（端口 3013，代理 /api 与 /static 到 5679）\n- `npm run generate` — 产出含 index.html 的静态站点（`.output/public`；`nuxt build` 不产 index.html，不能用于静态托管）\n\n### Desktop (`desktop/`，根目录 `npm run dist` 串联全流程)\n- `npm run dev` — 打包后端 bundle + Electron 窗口运行\n- `npm run build:backend` — esbuild 打包 backend/src → build/backend.mjs（ESM；externals: sharp/better-sqlite3/ffmpeg-static/ffprobe-static）\n- `npm run build:main` — 打包主进程 → dist/main.js\n- `npm run rebuild:native` — better-sqlite3 按 Electron ABI 重编（原生模块 ABI 变化后必须执行；postinstall 已自动做）\n- `npm run dist` — prepare-resources + electron-builder 出 arm64/x64 dmg → release/\n- `npm run dist:win` — 交叉打包 Windows NSIS 安装器（win-x64）；win 版 ffmpeg.exe 缓存在 build/win-bin/（缺失时脚本提示下载地址）\n\n## Architecture\n\n### Backend\n- **HTTP**: Hono（入口 `src/index.ts`），路由挂 `/api/v1`，`/static` 服务 DATA_ROOT，生产托管前端静态目录\n- **Database**: SQLite（better-sqlite3 + WAL），`SQLITE_PATH` 覆盖库文件位置；DDL 在 `src/db/sqlite-schema.ts`，启动时幂等重放；Drizzle 表定义 `src/db/schema.ts`（sqlite-core）\n- **路径锚点**: `src/utils/paths.ts` 统一解析 DATA_ROOT/STORAGE_ROOT；桌面版由 Electron 主进程注入 env（`HUOBAO_DATA_DIR`/`SQLITE_PATH`/`WORKSPACE_PATH`/`FRONTEND_DIST`/`FFMPEG_BIN`/`FFPROBE_BIN`），dev 走仓库相对路径默认值\n- **AI Agents**: Mastra，4 个 agent（script_rewriter / extractor / storyboard_breaker / prompt_generator），instructions 从 `workspace/prompts/*.md` + skills 动态拼接，模型按请求解析；fetch 补丁链适配国内中转站（关思考/温度/max_tokens）\n- **媒体生成**: `services/generation.ts` 统一任务生命周期（sys_task 表），适配器模式：图片 openai/gemini/volcengine，视频 volcengine/minimax\n- **视频拼接**: `services/ffmpeg-merge.ts`，FFmpeg 二进制内置（ffmpeg-static），可用 `FFMPEG_BIN`/`FFPROBE_BIN` 覆盖\n\n### Frontend\n- Nuxt 3 SPA，动态路由在 `nuxt.config.ts` 的 `pages:extend` 手动注册（views/drama/）\n- `app/composables/useApi.ts` 统一 fetch 客户端（全相对路径，生产与后端同源）\n- 核心工作台 `app/views/drama/episode.vue`（剧本→制作→导出流水线）\n\n### Desktop\n- 主进程 `desktop/src/main.ts`：单实例锁 → 空闲端口 → userData 准备（workspace 模板 copy-once + `.template-version` 版本标记）→ `utilityProcess.fork` 后端 → 轮询 health → BrowserWindow\n- userData：打包版 `~/Library/Application Support/HuobaoDrama/`，dev 版 `HuobaoDrama-Dev/`（互不干扰）\n- 后端 bundle 在 asar 内（externals 经 asar node_modules 解析，.node 自动重定向 unpacked）\n\n## Database\nSQLite 单文件（默认 `data/huobao.sqlite3`，桌面版在 userData）。启动时 `initSqliteSchema` 幂等建表 + 风格预设种子。MySQL→SQLite 一次性迁移：`cd backend && npx tsx scripts/import-mysql-to-sqlite.ts [--force]`（逐表行数校验、写前备份）。\n\n## Key Config\n- AI 服务配置存 DB（`ai_service_configs` 表），设置页维护，不在配置文件\n- 环境变量全集见 README「环境变量」；`configs/config.yaml` 是死配置（勿参考）\n- `PUBLIC_BASE_URL`：Seedance 引用本地参考资源需公网地址，桌面版无此能力（有中文报错）\n"},"items":[{"name":"SKILL.md","path":"backend/workspace/skills/extractor/SKILL.md","rawUrl":"https://raw.githubusercontent.com/chatfire-AI/huobao-drama/HEAD/backend/workspace/skills/extractor/SKILL.md","title":"extractor","category":"anthropic-skill","format":"markdown","content":"---\nname: extractor\ndescription: 角色、场景和道具提取的规范与方法\n---\n\n# 角色、场景与道具提取指南\n\n## 角色提取规范\n\n提取的角色字段（与 `save_dedup_characters` 工具参数一一对应）：\n- **name**（必填）：角色全名\n- **role**：角色定位，主角/配角/龙套\n- **appearance**：样貌描写（300-500字）——性别、年龄感、五官、体态、气质。**角色的性格特点不要单独输出，要转化为外在气质与神态融入样貌描写**（例如\"性格冷峻\"应写为\"眼神冷峻、表情克制、少有笑意\"）\n- **styling**：妆造——发型、服装、妆面、配饰等\n- **description**：背景故事和人物关系（可选补充）\n\n## 场景提取规范\n\n提取的场景字段（与 `save_dedup_scenes` 工具参数一一对应）：\n- **location**（必填）：具体场所名称\n- **time**：时间段（如 白天/黄昏/深夜），同地点不同时段视为新场景\n- **prompt**：场景描述——空间、陈设、年代质感、关键视觉元素（纯背景，不含人物）\n- **lighting**：场景光影——光源、色调、明暗、氛围\n\n## 道具提取规范\n\n**核心原则：宁可少提，不要多提。** 道具是用来生成白底单品图、供视频特写引用的高成本资产，只有剧情关键道具才值得提取。一集通常 **0-3 个**关键道具，超过 3 个时按剧情重要性排序只保留前 3 个。\n\n必须**同时满足**以下两条，缺一不可：\n1. **直接推动剧情**：该物品的出现、交接、损坏或发现会引发情节转折（如凶器、信物、关键文件、定情礼物、关键证据）。\n2. **值得单独生成图片**：后续分镜会给它特写镜头或反复出现，需要固定外观。\n\n**判定三问**（对每个候选道具自问自答，任一答\"否\"即放弃）：\n- ① 删掉它剧情是否依然成立？→ 成立则**不提取**（它只是道具式背景板）\n- ② 它只是角色随手使用的日常物品吗（手机、筷子、水杯、香烟、雨伞）？→ 是则**不提取**\n- ③ 它是场景陈设的一部分吗（桌椅、灯具、门窗、挂画、餐具）？→ 是则**不提取**（这些属于场景描述）\n\n**不算道具的典型**：随手使用但不影响剧情走向的普通物品；场景陈设与家具；只被提及一次且再无下文的物品；角色的常规穿戴（归入角色妆造）。\n\n如果没有符合条件的道具，**不要强行提取**，调用 `save_dedup_props` 时传空数组即可。\n\n提取的道具字段（与 `save_dedup_props` 工具参数一一对应）：\n- **name**（必填）：道具名\n- **type**：类型——日常/武器/交通/装饰/文件等\n- **description**：物品外貌——只描写物品本身的物理外观（材质、颜色、形状、大小、新旧程度、磨损痕迹等），不要写剧情用途，不要涉及与角色或其他事物的关联\n\n道具**不需要输出图片提示词**——道具的最终提示词由提示词生成 Agent 在生图前专门生成（白底单品规范）。\n\n## 使用步骤\n\n1. 调用 `read_script_for_extraction` 读取当前集剧本\n2. 调用 `read_existing_characters` 查看项目已有角色和当前集已关联角色\n3. 调用 `read_existing_scenes` 查看项目已有场景和当前集已关联场景\n4. 调用 `read_existing_props` 查看项目已有道具和当前集已关联道具\n5. 只提取当前集真实涉及的角色、场景和道具\n6. 调用 `save_dedup_characters` 保存角色并自动关联到当前集\n7. 调用 `save_dedup_scenes` 保存场景并自动关联到当前集\n8. 调用 `save_dedup_props` 保存道具并自动关联到当前集\n\n## 当前集规则\n\n- 目标是补齐\"当前集\"需要的角色、场景和道具，不是重扫整个项目\n- 若已在项目中存在但当前集未关联，仍应复用并关联到当前集\n- 去重规则：角色/道具按名称精确匹配，场景按【地点+时间段】精确匹配，命中的优先复用，不要重复创建\n- 近名去重：名称带括号定位或别名时按括号前主体比较（如「林小雨（主角）」与「林小雨」视为同一角色/道具，复用已有）；read_existing_characters / read_existing_props 返回的 normalized_name 即归一化后的名字，场景的 normalized_location 同理，据此判断即可\n","frontmatter":{"name":"extractor","description":"角色、场景和道具提取的规范与方法"},"isInternal":false,"tokens":1607,"sizeBytes":4374},{"name":"SKILL.md","path":"backend/workspace/skills/prompt-generator/character-prompt/SKILL.md","rawUrl":"https://raw.githubusercontent.com/chatfire-AI/huobao-drama/HEAD/backend/workspace/skills/prompt-generator/character-prompt/SKILL.md","title":"character-prompt","category":"anthropic-skill","format":"markdown","content":"---\nname: character-prompt\ndescription: 角色最终提示词规范 — 正脸特写 + 三视图（character turnaround：正面/90 度侧面/背面），作为后续所有生成的形象锚点\n---\n\n# 角色最终提示词（左侧正脸特写 + 右侧三视图）\n\n生成的是一张角色设定参考图（character reference sheet），构图固定为：\n\n- **左侧：正脸特写**——头部与肩部的正面近景，五官、发型、肤质清晰可见，作为脸部辨识度的锚点\n- **右侧：并列展示正面、90 度侧面、背面三张等高全身视图**——同一角色的三个全身视图等高并排，头顶与脚底对齐\n\n**核心原则：一致性 > 美观。** 这张图是后续所有角色图片、视频参考的形象锚点，必须中性、清晰、可复用——不要追求单张图的艺术感。\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n角色设定参考图，左侧为正脸特写，右侧并列展示正面、90 度侧面、背面三张等高全身视图，\n特写与全身视图都是同一角色，全身入镜，中性 A 字站姿，三张全身视图等高并排、头顶脚底对齐，\n[年龄感 + 性别感 + 体态]，[五官特征]，[发型]，[服装 + 配饰]，\n正脸特写与三个视图的脸、发型和服装完全一致，\n纯白背景，柔和均匀的光线，电影质感\n```\n\n## 描述顺序规则\n\n把**最有辨识度的特征放在前面**，按此顺序落地 `appearance`（样貌）与 `styling`（妆造）的每个关键元素，不遗漏：\n\n1. 身份锚点：年龄感（如\"二十出头\"）、性别感、体态（高矮胖瘦、姿态习惯）\n2. 五官：脸型、眼睛、其他显著特征（疤、痣、眼镜等）——正脸特写尤其依赖这部分描写\n3. 发型：颜色、长度、样式\n4. 服装：款式、颜色、材质、状态（如\"袖口有焊锡痕迹的皱褶工服\"）\n5. 配饰：只写有辨识度的，不堆砌\n\n角色的性格特点要转化为外在气质与神态描写（如\"憔悴\" → \"眼神疲惫、肩膀微垮\"），不要直接出现性格词汇。\n\n## 构图与一致性\n\n- 左侧正脸特写：正面朝向镜头、中性表情、头顶到肩膀完整入镜\n- 右侧三张全身视图：同一角色的正面、90 度侧面、背面，**等高并排、间距均匀**，头顶与脚底在同一水平线上\n- 特写与三张全身视图必须是同一张脸、同一发型、同一服装——明确写出\"正脸特写与三张全身视图的脸、发型和服装完全一致\"\n- 中性站姿、自然表情——方便作为参考图复用\n- 柔和均匀的棚拍光，不要戏剧性光影（参考图要在各种场景下都能用）\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇\n\n## 禁止事项\n\n- 动态姿势、夸张表情、手持道具、与他人同框\n- 裁切身体（全身视图必须 full body，头顶到脚底完整入镜；特写必须头部肩部完整入镜）\n- 文字、标签、水印、签名\n- 重阴影、彩色背景光、背景道具\n\n## 保存\n\n调用 `save_character_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","frontmatter":{"name":"character-prompt","description":"角色最终提示词规范 — 正脸特写 + 三视图（character turnaround：正面/90 度侧面/背面），作为后续所有生成的形象锚点"},"isInternal":false,"tokens":1324,"sizeBytes":3235},{"name":"SKILL.md","path":"backend/workspace/skills/prompt-generator/prop-prompt/SKILL.md","rawUrl":"https://raw.githubusercontent.com/chatfire-AI/huobao-drama/HEAD/backend/workspace/skills/prompt-generator/prop-prompt/SKILL.md","title":"prop-prompt","category":"anthropic-skill","format":"markdown","content":"---\nname: prop-prompt\ndescription: 道具最终提示词规范 — 白底单品静物，标准产品摄影视角：比例准确、边缘完整、背景不承载叙事\n---\n\n# 道具最终提示词（白底单品 · 标准产品摄影）\n\n生成的是一张白底单品图（product shot）：**采用标准产品摄影视角**，画面中只有道具本身，孤立放置在纯白背景上，**不掺杂任何其他元素**——没有其他物品、没有人物、没有场景环境、没有手部持握。\n\n三条硬性要求：\n1. **物品各部分比例准确**——不要夸张、变形或风格化拉伸，道具的相对尺寸关系必须真实\n2. **边缘完整**——道具整体完整入镜，四周留白，任何部分都不得被画面边缘裁切\n3. **背景不承载任何叙事内容**——纯白背景只是衬底，不带场景感、不带情节暗示、不带装饰元素\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n单品产品图，标准产品摄影视角，[道具名 + 材质/颜色/形状/大小 + 新旧程度与磨损细节]，\n物品各部分比例准确，孤立放置在纯白背景上，居中完整入镜，边缘完整无裁切，\n背景纯净不承载任何叙事内容，无其他物品、无人物、无场景，\n柔和均匀的影棚光，轻淡阴影，高细节\n```\n\n## 生成规则\n\n- 以道具 `name`（名称）与 `description`（物品外貌）为核心：材质、颜色、形状、大小、新旧程度、磨损痕迹等物理细节**逐项落地**，这是道具辨识度的来源\n- 标准产品摄影视角：微俯视 3/4 视角（同时看清顶面与侧面，最有立体感）；扁平道具（纸张、证件、照片）用正俯视平铺\n- 单品居中完整呈现，四周留白，比例准确、边缘完整，不要裁切道具主体\n- 柔和均匀的影棚光，阴影轻淡，高细节\n- 只描写物品本身，不要提及剧情、角色或用途（背景与画面都不承载叙事内容）\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇；**不要**\"电影质感\"类词汇（道具图是产品图不是剧照）\n\n## 禁止事项\n\n- 手部持握、人物、其他物品、场景环境入镜\n- 包装、底座、展示架（除非它就是道具本体的一部分）\n- 文字、水印、签名（道具本体上印刷的文字图案可以保留并描述）\n- 环境反光、彩色光\n- 夸张透视、变形、比例失真、边缘裁切\n\n## 保存\n\n调用 `save_prop_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","frontmatter":{"name":"prop-prompt","description":"道具最终提示词规范 — 白底单品静物，标准产品摄影视角：比例准确、边缘完整、背景不承载叙事"},"isInternal":false,"tokens":1065,"sizeBytes":2642},{"name":"SKILL.md","path":"backend/workspace/skills/prompt-generator/scene-prompt/SKILL.md","rawUrl":"https://raw.githubusercontent.com/chatfire-AI/huobao-drama/HEAD/backend/workspace/skills/prompt-generator/scene-prompt/SKILL.md","title":"scene-prompt","category":"anthropic-skill","format":"markdown","content":"---\nname: scene-prompt\ndescription: 场景最终提示词规范 — 清晰广角建立镜头：前景/中景/后景/出入口/地面/墙面/主要陈设的固定相对位置，空间连续自洽可复用，无人物\n---\n\n# 场景最终提示词（广角建立镜头 · 无人物空镜）\n\n生成的是一张**清晰的广角建立镜头（establishing shot）**场景图：**完全没有人物**的纯场景空镜，完整展示**前景、中景、后景、出入口、地面、墙面及主要陈设的固定相对位置**，空间结构连续、自洽且可复用。\n\n这张图会作为该场景所有镜头的背景参考锚点：观众和模型都必须能从这张图读懂整个空间的布局——从哪里进出、地面与墙面是什么质感、核心陈设各自固定在什么位置。视角必须稳定、通用。\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n固定机位广角镜头，清晰的建立镜头，[地点 + 年代质感]，[时间段]，\n前景（[前景元素]）、中景（[中景主体空间]）、后景（[后景纵深]）三层分层构图，\n出入口（[门/通道的位置与样式]），地面（[地面材质与状态]），墙面（[墙面材质与颜色]），\n[主要陈设及其固定相对位置]，\n空间结构连续、自洽，\n[光源 + 色温 + 明暗对比]，[氛围]，\n画面中没有任何人物，空场景，电影质感\n```\n\n## 空间结构规则\n\n空间必须**读得懂、对得上、可复用**：\n\n- **前景**：框景/遮挡物（门框、桌角、植物、设备边缘），制造纵深——写出 1-2 个具体元素\n- **中景**：场景的主体空间与核心陈设（流水线、床铺、柜台）\n- **后景**：空间的延伸（远处的墙、窗、走廊、城市轮廓）\n- **出入口**：门、楼梯、通道的位置与样式必须明确（如\"画面左侧一扇铁门\"），这是后续镜头调度人物进出的依据\n- **地面与墙面**：材质、颜色、状态具体化（如\"水泥地面有油渍\"\"墙面石灰斑驳\"）\n- **主要陈设**：写出 2-4 个核心陈设及它们的**固定相对位置**（如\"流水线沿墙排开，尽头是吧台\"），陈设之间的左右/远近关系要自洽，不要只罗列物品名\n\n## 人物（硬性规则 · 最高优先级）\n\n**场景图中不能出现任何的人，只保留场景本身。**\n\n- 提示词中不描述人物、不提及任何与人物相关的内容\n- 场景描述（prompt）中出现的人物信息一律忽略，不写入提示词\n- 提示词结尾必须包含：\"画面中没有任何人物，空场景\"\n\n`prompt`（场景描述）中的陈设、年代质感、关键视觉元素必须全部落地；`lighting`（场景光影）要具体化：光源方向、色温冷暖、明暗对比（如\"头顶灯管发出冷白光，机器下方投下硬阴影\"）。\n\n## 视角与氛围\n\n- 稳定的平视或微俯广角，不要极端俯仰、鱼眼、倾斜构图（要作为固定场景反复复用）\n- 以 `location` + `time` 确定时间段与光线基调（日/夜/黄昏的光完全不同）\n- 氛围词具体化：\"压抑\" → \"空气闷热、光线昏暗低沉\"，不要只写抽象情绪词\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇\n\n## 禁止事项\n\n- 任何人物——**场景图中不能出现任何的人，只保留场景本身**\n- 文字、招牌上的可读文字、水印、签名\n- 动态模糊、运动中的物体（场景参考图必须静止稳定）\n- 只罗列陈设清单而不交代相对位置（空间结构必须连续、自洽）\n\n## 保存\n\n调用 `save_scene_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n","frontmatter":{"name":"scene-prompt","description":"场景最终提示词规范 — 清晰广角建立镜头：前景/中景/后景/出入口/地面/墙面/主要陈设的固定相对位置，空间连续自洽可复用，无人物"},"isInternal":false,"tokens":1486,"sizeBytes":3758},{"name":"SKILL.md","path":"backend/workspace/skills/prompt-generator/video-prompt/SKILL.md","rawUrl":"https://raw.githubusercontent.com/chatfire-AI/huobao-drama/HEAD/backend/workspace/skills/prompt-generator/video-prompt/SKILL.md","title":"video-prompt","category":"anthropic-skill","format":"markdown","content":"---\nname: video-prompt\ndescription: 视频提示词规范 — 根据分镜段落内容生成按时间分段、段内可切镜的视频生成提示词\n---\n\n# 视频提示词（分镜段落 → video_prompt）\n\n根据单个分镜段落的 description（含【镜头N】子镜头结构与台词/旁白）/ atmosphere / duration，生成驱动 AI 视频生成的 `video_prompt`。**一个分镜段落 = 一段 8-15 秒的视频，内部允许切镜**：段与段之间可以是不同镜头（换景别/角度/对象），用硬切衔接；但**全程不跨场景**、不闪回。\n\n## 格式\n\n`video_prompt` 的**第一行是信息头**：先介绍这条视频有哪些人物和场景，然后再接时间分段。人物、场景一律用 @ 引用（生成时会替换为对应参考图片标记，让视频模型先对上\"谁\"和\"在哪\"）。\n\n```\n出场人物：@小明、@小红；场景：@咖啡厅。\n0-3秒：@咖啡厅，近景固定镜头，@小明低头看手机，手指反复敲桌面，表情焦虑。\n3-6秒：切到门口全景，门铃响，@小红推门走入，带进一阵冷风。\n6-9秒：切回中景，@小红微笑着走向小明坐下，小明说：「你终于来了。」\n```\n\n信息头规则：\n- 只列该分镜段落实际出场的人物和绑定的场景，不要列没出场的\n- 有明显道具出场时可在信息头追加（如 `；道具：@信件`）\n- 信息头独立一行，以句号结尾，之后是时间分段\n\n按 3 秒为一段，每段单独一行、用换行分隔，时间范围连续衔接（无重叠、无空缺）。\n\n## 与分镜描述的映射\n\n`description` 是 video_prompt 的唯一内容来源（画面、动作、台词、旁白都在其中），转换规则：\n\n- `description` 的每个 `【镜头N】` 映射为 **1-2 个连续的 3 秒段**，顺序一致、不遗漏、不合并、不新增子镜头\n- 台词/旁白从对应 `【镜头N】` 内的「角色名说：「…」」「旁白：…」提取，分配到该子镜头映射的段；**不要创作 description 之外的新台词**\n- 画面动作以 `description` 为准；`atmosphere` 只用于补各段的光线、色调与氛围描写\n\n## 段内结构\n\n每一段按此顺序组织内容（可省略无内容的项，但动作/画面必须有）：\n\n**时间范围 ＋ 场景@引用 ＋ 景别/运镜 ＋ 角色@引用＋主体动作·表情 ＋ 对白/旁白 ＋ 氛围光线**\n\n- **第一段必须建立空间**：场景 + 机位 + 角色的位置与状态，让观众一眼知道在哪、看谁\n- **切镜**：切镜后的段开头用\"切到/切回\"等衔接词，并重新交代景别与主体；切镜点应对齐分镜 `description` 中的 `【镜头N】` 结构\n- **景别/运镜**：每段一个镜头状态（近景/中景/全景/特写；固定/推/拉/摇/跟）；单个子镜头内运镜连续，切镜后可更换运镜方式\n- **动作**：每段一个主动作，动词具体可见（走、转身、抬头、攥紧、停顿）\n- **情绪全部转为可见描写**：不要\"他很伤心/气氛紧张\"这类抽象词，写成\"他低下头、手指攥紧杯沿、呼吸变重\"\n- **对白/旁白**：写「角色名说：「台词」」，旁白写「旁白：内容」；3 秒念不完的长台词拆到多段；无对白的段可写环境音/动作音（如\"机器持续轰鸣\"）\n\n## 引用规则\n\n- `@场景名` — 场景引用，名字必须与场景列表中的地点完全一致\n- `@角色名` — 角色引用，名字必须与角色列表中的名字完全一致\n- `@道具名` — 道具引用，名字必须与道具列表中的名字完全一致；道具在画面中明显可见、被使用或特写时引用\n- 生成时会自动把 `@名字` 替换为对应参考图片标记（如 `@小明` → `@图片1小明`），因此名字必须精确匹配，不要缩写或加额外符号\n- **每段至少一个 @ 引用锚定画面**；角色出场的段必须 @ 该角色；只引用该分镜段落已绑定的场景/角色/道具\n\n## 时间轴规则\n\n- 段数 = 分镜段落 duration ÷ 3 秒（向上取整），各段时间范围相加必须等于段落总时长\n- 内容节奏：第一段建立 → 中段推进动作/冲突 → 末段落到结果或情绪点\n\n## 禁止事项\n\n- 跨场景切换、闪回（一个段落只发生在一个场景内）\n- 引用列表之外的场景/角色名\n- 抽象心理描写、文学化比喻（模型只认可见画面）\n- 语言与会话语言指令不符\n\n## 保存\n\n调用 `update_storyboard` 仅更新该分镜段落的 `video_prompt` 字段，不要改动其他字段，不要重新拆分整集。\n","frontmatter":{"name":"video-prompt","description":"视频提示词规范 — 根据分镜段落内容生成按时间分段、段内可切镜的视频生成提示词"},"isInternal":false,"tokens":1809,"sizeBytes":4586},{"name":"SKILL.md","path":"backend/workspace/skills/script-rewriter/SKILL.md","rawUrl":"https://raw.githubusercontent.com/chatfire-AI/huobao-drama/HEAD/backend/workspace/skills/script-rewriter/SKILL.md","title":"script-rewriter","category":"anthropic-skill","format":"markdown","content":"---\nname: script-rewriter\ndescription: 小说改写为格式化剧本的方法论和规范\n---\n\n# 剧本改写指南\n\n## 改写原则\n\n1. **保留核心情节**：不改变主线故事和角色关系\n2. **增强画面感**：将叙述性文字转化为可视化的场景描写\n3. **对话驱动**：用对白推动情节，减少旁白\n4. **节奏把控**：每场戏控制在 30-60 秒，适合短视频\n5. **不写镜头语言**：不涉及景别、角度、运镜，这些属于分镜拆解步骤\n\n## 格式化剧本格式\n\n```\n## S01 | 内景 · 咖啡厅 | 黄昏\n\n黄昏的光线透过落地窗洒进咖啡厅，吧台上咖啡杯热气升腾。\n\n小明独自坐在角落卡座，低头看手机，神情有些焦虑。\n\n门铃响起，小红推门而入。她看到小明，微笑着走过去。\n\n小红：（微笑）等很久了吗？\n小明：（抬头）还好，刚到。\n```\n\n### 格式规则\n\n- `## S编号 | 内景/外景 · 地点 | 时间段` — 场景头\n- 动作描写自然段 — 不包含任何镜头语言\n- `角色名：（状态/表情）台词内容` — 对白格式\n\n### 内容量参考\n\n格式化剧本相比原始内容增加约 20-30%，主要增量是场景头标记和对白格式化，不是扩写。\n\n## 改写步骤\n\n1. 先调用 `read_episode_script` 读取原始内容\n2. 分析内容结构（对话、叙述、心理描写的比例）\n3. 调用 `rewrite_to_screenplay` 执行改写\n4. 检查改写结果，确认符合格式化剧本格式\n5. 调用 `save_script` 保存最终结果\n\n## 注意事项\n\n- 心理描写可转化为角色表情/动作或画外音\n- 长段叙述拆分为多个短场景\n- 确保每个场景有明确的情绪转折点\n- 保持角色语言风格一致性\n- 场景编号连续递增（S01, S02, S03...）\n- 时间段要具体（黄昏、深夜、清晨），不要笼统写\"白天\"\n","frontmatter":{"name":"script-rewriter","description":"小说改写为格式化剧本的方法论和规范"},"isInternal":false,"tokens":758,"sizeBytes":1848},{"name":"SKILL.md","path":"backend/workspace/skills/storyboard-breaker/SKILL.md","rawUrl":"https://raw.githubusercontent.com/chatfire-AI/huobao-drama/HEAD/backend/workspace/skills/storyboard-breaker/SKILL.md","title":"storyboard-breaker","category":"anthropic-skill","format":"markdown","content":"---\nname: storyboard-breaker\ndescription: 分镜拆解专业规范 — 将剧本拆分为可承载多个子镜头的分镜段落\n---\n\n# 分镜拆解指南\n\n## 核心定义：分镜段落\n\n一个分镜 = 一个 **分镜段落**（segment）= 一个视频生成任务。\n\n- 每个段落时长 **8-15 秒**，内部承载 **2-4 个子镜头**\n- 子镜头之间**可以切镜**：换景别、换角度、换拍摄对象，用硬切衔接\n- 子镜头之间**不跨场景**：一个段落只发生在一个场景内（`scene_id` 是段落级绑定）\n- 每个子镜头 2-6 秒，聚焦一个画面单元（一个动作、一个反应、一个特写）\n\n## 拆分流程（四步）\n\n1. 调用 `read_storyboard_context` 读取剧本、角色、场景、道具、已有分镜摘要\n2. **节拍识别**：先识别剧本的叙事节拍——剧本中的【开场】【触发】【高潮】【收尾】等标记，或叙事转折点（地点转移、规则揭示、情绪爆发、反转）。**节拍边界强制切段**，同一节拍内的子镜头优先归入同一段落，不把一条因果链（铺垫-发生-反应）切散到不同段落\n3. **总量锚定**：目标总时长 = 剧本字数 ÷ 500字/分钟；段落数 ≈ 目标总时长 ÷ 12秒，允许 ±20% 浮动。不要明显超出或不足\n4. **段落内拆子镜头**：按动作切换点、视角切换点、对象切换点切分子镜头，为每个段落补全完整字段后调用 `save_storyboards` 一次性保存\n\n## 节奏分层时长\n\n按段落功能确定时长，不要一刀切：\n\n| 段落类型 | 时长 | 说明 |\n|---|---|---|\n| 过渡段 | 8-10 秒 | 赶路、空镜、环境建立、转场 |\n| 叙事段 | 10-15 秒 | 常规剧情推进、对话 |\n| 爆点段 | 12-15 秒 | 特写、规则揭示、情感爆发、反转；子镜头节奏放慢，单个子镜头可停留 4-6 秒 |\n\n## 台词时长下限（硬规则）\n\n**段落时长 ≥ 段内台词与旁白总字数（写在 description 中的部分）÷ 4.5字/秒 + 2秒表演余量**\n\n装不下的台词必须拆到下一个段落，不允许把演不完的台词塞进一个段落。\n\n## 镜头要素\n\n1. **镜头标题**：3-5字概括段落核心内容（如\"噩梦惊醒\"）\n2. **时间**：具体时分 + 光线描述\n3. **地点**：场景完整描述 + 空间布局 + 环境细节\n4. **景别**：段落内主导景别；多景别段落写组合，如\"中景+特写\"\n5. **角度**：平视/仰视/俯视/侧面/背面\n6. **运镜**：固定/推镜/拉镜/摇镜/跟镜/移镜（段落内不同子镜头可不同）\n7. **画面描述** `description`：按 `【镜头1】…【镜头2】…` 逐子镜头描述观众实际看到和听到的内容——画面（谁 + 具体动作 + 肢体细节 + 表情）写在前；该子镜头有台词时以「角色名说：「台词」」写在对应 `【镜头N】` 内，旁白写「旁白：内容」\n8. **画面结果** `result`：段落结尾的即时后果 + 视觉细节\n9. **氛围** `atmosphere`：光线 + 色调 + 声音 + 整体氛围\n10. **时长** `duration`：段落总时长 8-15 秒，且满足台词时长下限\n11. **场景关联**：若能匹配已有场景，必须填写 `scene_id`\n12. **角色关联**：填写 `character_ids`，绑定当前段落涉及的 0 到多个角色\n13. **道具关联**：填写 `prop_ids`，绑定当前段落出现的关键道具（0 到多个）\n\n## 场景关联规则\n\n- 优先使用 `read_storyboard_context` 返回的 `scenes`\n- `location + time` 可明确匹配时，必须回填正确 `scene_id`\n- 不要凭空生成不存在的场景 ID\n- 如果剧本内容明显落在已有场景中，不要重复创造新场景描述\n\n## 角色绑定规则\n\n- `character_ids` 必须从 `read_storyboard_context` 返回的角色列表中选择\n- 一个段落可以没有角色，也可以绑定多个角色\n- 只要段落里有明确出场、被看见、发生动作或说话的角色，都应绑定进去\n- 纯环境段落、空镜、物件特写可以传空数组\n\n## 道具绑定规则\n\n- `prop_ids` 必须从 `read_storyboard_context` 返回的道具列表（`props`）中选择\n- 道具被角色使用、交接、特写，或在画面中明显可见且对叙事有意义时，必须绑定到该段落\n- 道具特写段落（无角色）也应绑定道具，`character_ids` 可为空\n- 与剧情无关的背景物品、场景陈设不要绑定；没有道具出现的段落传空数组\n- 绑定的道具会作为视频生成的参考图（白底单品图），保证道具外观跨段落一致\n\n## 质量要求\n\n- `description` 要适合人读，按子镜头详细描述观众实际看到和听到的内容；台词/旁白直接写在对应 `【镜头N】` 内\n- `image_prompt` 要突出单帧构图、角色外观、环境和光线（对应段落第一个子镜头）\n- `bgm_prompt` 和 `sound_effect` 用简洁短语即可，但不能空泛到只有“紧张”“悲伤”\n- 如需调整，调用 `update_storyboard` 修改具体段落\n","frontmatter":{"name":"storyboard-breaker","description":"分镜拆解专业规范 — 将剧本拆分为可承载多个子镜头的分镜段落"},"isInternal":false,"tokens":1991,"sizeBytes":4966},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/chatfire-AI/huobao-drama/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# CLAUDE.md\n\n## Project Overview\n\n火宝短剧（Huobao Drama）— AI 短剧/漫剧一站式制作工具。全 TypeScript 栈：小说 → 剧本改写 → 资产提取 → 生图 → 分镜拆解 → 生视频 → FFmpeg 拼接导出。支持 Electron 桌面版（macOS dmg）与服务器部署。\n\n## Structure\n\n```\nbackend/   — Hono + Drizzle ORM (better-sqlite3) + Mastra (AI agents)\nbackend/workspace/ — Agent 工作目录（Mastra Workspace jail 根）\nbackend/workspace/skills/ — Agent SKILL.md definitions（设置页可在线编辑）\nfrontend/  — Nuxt 3 + Vue 3 + TypeScript，ssr:false（纯 CSS，无 UI 框架）\ndesktop/   — Electron 桌面版：主进程 + esbuild 打包脚本 + electron-builder 配置\ndata/      — SQLite 数据库（huobao.sqlite3）+ 生成的静态文件（static/）\nconfigs/   — 遗留死配置，代码零引用\n```\n\n## Commands\n\n### Backend (`backend/`)\n- `npm run dev` — tsx watch 开发服务（端口 5679）\n- `npm start` — tsx 生产启动\n- `npm run typecheck` — TypeScript 类型检查\n- `npm run backfill-artwork` — 存量图片/视频补缩略图与海报帧\n\n### Frontend (`frontend/`)\n- `npm run dev` — Vite 开发服务（端口 3013，代理 /api 与 /static 到 5679）\n- `npm run generate` — 产出含 index.html 的静态站点（`.output/public`；`nuxt build` 不产 index.html，不能用于静态托管）\n\n### Desktop (`desktop/`，根目录 `npm run dist` 串联全流程)\n- `npm run dev` — 打包后端 bundle + Electron 窗口运行\n- `npm run build:backend` — esbuild 打包 backend/src → build/backend.mjs（ESM；externals: sharp/better-sqlite3/ffmpeg-static/ffprobe-static）\n- `npm run build:main` — 打包主进程 → dist/main.js\n- `npm run rebuild:native` — better-sqlite3 按 Electron ABI 重编（原生模块 ABI 变化后必须执行；postinstall 已自动做）\n- `npm run dist` — prepare-resources + electron-builder 出 arm64/x64 dmg → release/\n- `npm run dist:win` — 交叉打包 Windows NSIS 安装器（win-x64）；win 版 ffmpeg.exe 缓存在 build/win-bin/（缺失时脚本提示下载地址）\n\n## Architecture\n\n### Backend\n- **HTTP**: Hono（入口 `src/index.ts`），路由挂 `/api/v1`，`/static` 服务 DATA_ROOT，生产托管前端静态目录\n- **Database**: SQLite（better-sqlite3 + WAL），`SQLITE_PATH` 覆盖库文件位置；DDL 在 `src/db/sqlite-schema.ts`，启动时幂等重放；Drizzle 表定义 `src/db/schema.ts`（sqlite-core）\n- **路径锚点**: `src/utils/paths.ts` 统一解析 DATA_ROOT/STORAGE_ROOT；桌面版由 Electron 主进程注入 env（`HUOBAO_DATA_DIR`/`SQLITE_PATH`/`WORKSPACE_PATH`/`FRONTEND_DIST`/`FFMPEG_BIN`/`FFPROBE_BIN`），dev 走仓库相对路径默认值\n- **AI Agents**: Mastra，4 个 agent（script_rewriter / extractor / storyboard_breaker / prompt_generator），instructions 从 `workspace/prompts/*.md` + skills 动态拼接，模型按请求解析；fetch 补丁链适配国内中转站（关思考/温度/max_tokens）\n- **媒体生成**: `services/generation.ts` 统一任务生命周期（sys_task 表），适配器模式：图片 openai/gemini/volcengine，视频 volcengine/minimax\n- **视频拼接**: `services/ffmpeg-merge.ts`，FFmpeg 二进制内置（ffmpeg-static），可用 `FFMPEG_BIN`/`FFPROBE_BIN` 覆盖\n\n### Frontend\n- Nuxt 3 SPA，动态路由在 `nuxt.config.ts` 的 `pages:extend` 手动注册（views/drama/）\n- `app/composables/useApi.ts` 统一 fetch 客户端（全相对路径，生产与后端同源）\n- 核心工作台 `app/views/drama/episode.vue`（剧本→制作→导出流水线）\n\n### Desktop\n- 主进程 `desktop/src/main.ts`：单实例锁 → 空闲端口 → userData 准备（workspace 模板 copy-once + `.template-version` 版本标记）→ `utilityProcess.fork` 后端 → 轮询 health → BrowserWindow\n- userData：打包版 `~/Library/Application Support/HuobaoDrama/`，dev 版 `HuobaoDrama-Dev/`（互不干扰）\n- 后端 bundle 在 asar 内（externals 经 asar node_modules 解析，.node 自动重定向 unpacked）\n\n## Database\nSQLite 单文件（默认 `data/huobao.sqlite3`，桌面版在 userData）。启动时 `initSqliteSchema` 幂等建表 + 风格预设种子。MySQL→SQLite 一次性迁移：`cd backend && npx tsx scripts/import-mysql-to-sqlite.ts [--force]`（逐表行数校验、写前备份）。\n\n## Key Config\n- AI 服务配置存 DB（`ai_service_configs` 表），设置页维护，不在配置文件\n- 环境变量全集见 README「环境变量」；`configs/config.yaml` 是死配置（勿参考）\n- `PUBLIC_BASE_URL`：Seedance 引用本地参考资源需公网地址，桌面版无此能力（有中文报错）\n","isInternal":false,"tokens":1509,"sizeBytes":4693}],"systemPromptSnippet":"<yakaai_skills repo=\"chatfire-AI/huobao-drama\">\n<!-- File: backend/workspace/skills/extractor/SKILL.md (Tokens: ~1607 | Category: anthropic-skill) -->\n---\nname: extractor\ndescription: 角色、场景和道具提取的规范与方法\n---\n\n# 角色、场景与道具提取指南\n\n## 角色提取规范\n\n提取的角色字段（与 `save_dedup_characters` 工具参数一一对应）：\n- **name**（必填）：角色全名\n- **role**：角色定位，主角/配角/龙套\n- **appearance**：样貌描写（300-500字）——性别、年龄感、五官、体态、气质。**角色的性格特点不要单独输出，要转化为外在气质与神态融入样貌描写**（例如\"性格冷峻\"应写为\"眼神冷峻、表情克制、少有笑意\"）\n- **styling**：妆造——发型、服装、妆面、配饰等\n- **description**：背景故事和人物关系（可选补充）\n\n## 场景提取规范\n\n提取的场景字段（与 `save_dedup_scenes` 工具参数一一对应）：\n- **location**（必填）：具体场所名称\n- **time**：时间段（如 白天/黄昏/深夜），同地点不同时段视为新场景\n- **prompt**：场景描述——空间、陈设、年代质感、关键视觉元素（纯背景，不含人物）\n- **lighting**：场景光影——光源、色调、明暗、氛围\n\n## 道具提取规范\n\n**核心原则：宁可少提，不要多提。** 道具是用来生成白底单品图、供视频特写引用的高成本资产，只有剧情关键道具才值得提取。一集通常 **0-3 个**关键道具，超过 3 个时按剧情重要性排序只保留前 3 个。\n\n必须**同时满足**以下两条，缺一不可：\n1. **直接推动剧情**：该物品的出现、交接、损坏或发现会引发情节转折（如凶器、信物、关键文件、定情礼物、关键证据）。\n2. **值得单独生成图片**：后续分镜会给它特写镜头或反复出现，需要固定外观。\n\n**判定三问**（对每个候选道具自问自答，任一答\"否\"即放弃）：\n- ① 删掉它剧情是否依然成立？→ 成立则**不提取**（它只是道具式背景板）\n- ② 它只是角色随手使用的日常物品吗（手机、筷子、水杯、香烟、雨伞）？→ 是则**不提取**\n- ③ 它是场景陈设的一部分吗（桌椅、灯具、门窗、挂画、餐具）？→ 是则**不提取**（这些属于场景描述）\n\n**不算道具的典型**：随手使用但不影响剧情走向的普通物品；场景陈设与家具；只被提及一次且再无下文的物品；角色的常规穿戴（归入角色妆造）。\n\n如果没有符合条件的道具，**不要强行提取**，调用 `save_dedup_props` 时传空数组即可。\n\n提取的道具字段（与 `save_dedup_props` 工具参数一一对应）：\n- **name**（必填）：道具名\n- **type**：类型——日常/武器/交通/装饰/文件等\n- **description**：物品外貌——只描写物品本身的物理外观（材质、颜色、形状、大小、新旧程度、磨损痕迹等），不要写剧情用途，不要涉及与角色或其他事物的关联\n\n道具**不需要输出图片提示词**——道具的最终提示词由提示词生成 Agent 在生图前专门生成（白底单品规范）。\n\n## 使用步骤\n\n1. 调用 `read_script_for_extraction` 读取当前集剧本\n2. 调用 `read_existing_characters` 查看项目已有角色和当前集已关联角色\n3. 调用 `read_existing_scenes` 查看项目已有场景和当前集已关联场景\n4. 调用 `read_existing_props` 查看项目已有道具和当前集已关联道具\n5. 只提取当前集真实涉及的角色、场景和道具\n6. 调用 `save_dedup_characters` 保存角色并自动关联到当前集\n7. 调用 `save_dedup_scenes` 保存场景并自动关联到当前集\n8. 调用 `save_dedup_props` 保存道具并自动关联到当前集\n\n## 当前集规则\n\n- 目标是补齐\"当前集\"需要的角色、场景和道具，不是重扫整个项目\n- 若已在项目中存在但当前集未关联，仍应复用并关联到当前集\n- 去重规则：角色/道具按名称精确匹配，场景按【地点+时间段】精确匹配，命中的优先复用，不要重复创建\n- 近名去重：名称带括号定位或别名时按括号前主体比较（如「林小雨（主角）」与「林小雨」视为同一角色/道具，复用已有）；read_existing_characters / read_existing_props 返回的 normalized_name 即归一化后的名字，场景的 normalized_location 同理，据此判断即可\n\n<!-- File: backend/workspace/skills/prompt-generator/character-prompt/SKILL.md (Tokens: ~1324 | Category: anthropic-skill) -->\n---\nname: character-prompt\ndescription: 角色最终提示词规范 — 正脸特写 + 三视图（character turnaround：正面/90 度侧面/背面），作为后续所有生成的形象锚点\n---\n\n# 角色最终提示词（左侧正脸特写 + 右侧三视图）\n\n生成的是一张角色设定参考图（character reference sheet），构图固定为：\n\n- **左侧：正脸特写**——头部与肩部的正面近景，五官、发型、肤质清晰可见，作为脸部辨识度的锚点\n- **右侧：并列展示正面、90 度侧面、背面三张等高全身视图**——同一角色的三个全身视图等高并排，头顶与脚底对齐\n\n**核心原则：一致性 > 美观。** 这张图是后续所有角色图片、视频参考的形象锚点，必须中性、清晰、可复用——不要追求单张图的艺术感。\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n角色设定参考图，左侧为正脸特写，右侧并列展示正面、90 度侧面、背面三张等高全身视图，\n特写与全身视图都是同一角色，全身入镜，中性 A 字站姿，三张全身视图等高并排、头顶脚底对齐，\n[年龄感 + 性别感 + 体态]，[五官特征]，[发型]，[服装 + 配饰]，\n正脸特写与三个视图的脸、发型和服装完全一致，\n纯白背景，柔和均匀的光线，电影质感\n```\n\n## 描述顺序规则\n\n把**最有辨识度的特征放在前面**，按此顺序落地 `appearance`（样貌）与 `styling`（妆造）的每个关键元素，不遗漏：\n\n1. 身份锚点：年龄感（如\"二十出头\"）、性别感、体态（高矮胖瘦、姿态习惯）\n2. 五官：脸型、眼睛、其他显著特征（疤、痣、眼镜等）——正脸特写尤其依赖这部分描写\n3. 发型：颜色、长度、样式\n4. 服装：款式、颜色、材质、状态（如\"袖口有焊锡痕迹的皱褶工服\"）\n5. 配饰：只写有辨识度的，不堆砌\n\n角色的性格特点要转化为外在气质与神态描写（如\"憔悴\" → \"眼神疲惫、肩膀微垮\"），不要直接出现性格词汇。\n\n## 构图与一致性\n\n- 左侧正脸特写：正面朝向镜头、中性表情、头顶到肩膀完整入镜\n- 右侧三张全身视图：同一角色的正面、90 度侧面、背面，**等高并排、间距均匀**，头顶与脚底在同一水平线上\n- 特写与三张全身视图必须是同一张脸、同一发型、同一服装——明确写出\"正脸特写与三张全身视图的脸、发型和服装完全一致\"\n- 中性站姿、自然表情——方便作为参考图复用\n- 柔和均匀的棚拍光，不要戏剧性光影（参考图要在各种场景下都能用）\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇\n\n## 禁止事项\n\n- 动态姿势、夸张表情、手持道具、与他人同框\n- 裁切身体（全身视图必须 full body，头顶到脚底完整入镜；特写必须头部肩部完整入镜）\n- 文字、标签、水印、签名\n- 重阴影、彩色背景光、背景道具\n\n## 保存\n\n调用 `save_character_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n\n<!-- File: backend/workspace/skills/prompt-generator/prop-prompt/SKILL.md (Tokens: ~1065 | Category: anthropic-skill) -->\n---\nname: prop-prompt\ndescription: 道具最终提示词规范 — 白底单品静物，标准产品摄影视角：比例准确、边缘完整、背景不承载叙事\n---\n\n# 道具最终提示词（白底单品 · 标准产品摄影）\n\n生成的是一张白底单品图（product shot）：**采用标准产品摄影视角**，画面中只有道具本身，孤立放置在纯白背景上，**不掺杂任何其他元素**——没有其他物品、没有人物、没有场景环境、没有手部持握。\n\n三条硬性要求：\n1. **物品各部分比例准确**——不要夸张、变形或风格化拉伸，道具的相对尺寸关系必须真实\n2. **边缘完整**——道具整体完整入镜，四周留白，任何部分都不得被画面边缘裁切\n3. **背景不承载任何叙事内容**——纯白背景只是衬底，不带场景感、不带情节暗示、不带装饰元素\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n单品产品图，标准产品摄影视角，[道具名 + 材质/颜色/形状/大小 + 新旧程度与磨损细节]，\n物品各部分比例准确，孤立放置在纯白背景上，居中完整入镜，边缘完整无裁切，\n背景纯净不承载任何叙事内容，无其他物品、无人物、无场景，\n柔和均匀的影棚光，轻淡阴影，高细节\n```\n\n## 生成规则\n\n- 以道具 `name`（名称）与 `description`（物品外貌）为核心：材质、颜色、形状、大小、新旧程度、磨损痕迹等物理细节**逐项落地**，这是道具辨识度的来源\n- 标准产品摄影视角：微俯视 3/4 视角（同时看清顶面与侧面，最有立体感）；扁平道具（纸张、证件、照片）用正俯视平铺\n- 单品居中完整呈现，四周留白，比例准确、边缘完整，不要裁切道具主体\n- 柔和均匀的影棚光，阴影轻淡，高细节\n- 只描写物品本身，不要提及剧情、角色或用途（背景与画面都不承载叙事内容）\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇；**不要**\"电影质感\"类词汇（道具图是产品图不是剧照）\n\n## 禁止事项\n\n- 手部持握、人物、其他物品、场景环境入镜\n- 包装、底座、展示架（除非它就是道具本体的一部分）\n- 文字、水印、签名（道具本体上印刷的文字图案可以保留并描述）\n- 环境反光、彩色光\n- 夸张透视、变形、比例失真、边缘裁切\n\n## 保存\n\n调用 `save_prop_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n\n<!-- File: backend/workspace/skills/prompt-generator/scene-prompt/SKILL.md (Tokens: ~1486 | Category: anthropic-skill) -->\n---\nname: scene-prompt\ndescription: 场景最终提示词规范 — 清晰广角建立镜头：前景/中景/后景/出入口/地面/墙面/主要陈设的固定相对位置，空间连续自洽可复用，无人物\n---\n\n# 场景最终提示词（广角建立镜头 · 无人物空镜）\n\n生成的是一张**清晰的广角建立镜头（establishing shot）**场景图：**完全没有人物**的纯场景空镜，完整展示**前景、中景、后景、出入口、地面、墙面及主要陈设的固定相对位置**，空间结构连续、自洽且可复用。\n\n这张图会作为该场景所有镜头的背景参考锚点：观众和模型都必须能从这张图读懂整个空间的布局——从哪里进出、地面与墙面是什么质感、核心陈设各自固定在什么位置。视角必须稳定、通用。\n\n## 输出结构（按此顺序组装单段连贯描述，语言跟随会话语言指令）\n\n```\n固定机位广角镜头，清晰的建立镜头，[地点 + 年代质感]，[时间段]，\n前景（[前景元素]）、中景（[中景主体空间]）、后景（[后景纵深]）三层分层构图，\n出入口（[门/通道的位置与样式]），地面（[地面材质与状态]），墙面（[墙面材质与颜色]），\n[主要陈设及其固定相对位置]，\n空间结构连续、自洽，\n[光源 + 色温 + 明暗对比]，[氛围]，\n画面中没有任何人物，空场景，电影质感\n```\n\n## 空间结构规则\n\n空间必须**读得懂、对得上、可复用**：\n\n- **前景**：框景/遮挡物（门框、桌角、植物、设备边缘），制造纵深——写出 1-2 个具体元素\n- **中景**：场景的主体空间与核心陈设（流水线、床铺、柜台）\n- **后景**：空间的延伸（远处的墙、窗、走廊、城市轮廓）\n- **出入口**：门、楼梯、通道的位置与样式必须明确（如\"画面左侧一扇铁门\"），这是后续镜头调度人物进出的依据\n- **地面与墙面**：材质、颜色、状态具体化（如\"水泥地面有油渍\"\"墙面石灰斑驳\"）\n- **主要陈设**：写出 2-4 个核心陈设及它们的**固定相对位置**（如\"流水线沿墙排开，尽头是吧台\"），陈设之间的左右/远近关系要自洽，不要只罗列物品名\n\n## 人物（硬性规则 · 最高优先级）\n\n**场景图中不能出现任何的人，只保留场景本身。**\n\n- 提示词中不描述人物、不提及任何与人物相关的内容\n- 场景描述（prompt）中出现的人物信息一律忽略，不写入提示词\n- 提示词结尾必须包含：\"画面中没有任何人物，空场景\"\n\n`prompt`（场景描述）中的陈设、年代质感、关键视觉元素必须全部落地；`lighting`（场景光影）要具体化：光源方向、色温冷暖、明暗对比（如\"头顶灯管发出冷白光，机器下方投下硬阴影\"）。\n\n## 视角与氛围\n\n- 稳定的平视或微俯广角，不要极端俯仰、鱼眼、倾斜构图（要作为固定场景反复复用）\n- 以 `location` + `time` 确定时间段与光线基调（日/夜/黄昏的光完全不同）\n- 氛围词具体化：\"压抑\" → \"空气闷热、光线昏暗低沉\"，不要只写抽象情绪词\n- 输出使用会话语言指令指定的目标语言，不要混入无关词汇\n\n## 禁止事项\n\n- 任何人物——**场景图中不能出现任何的人，只保留场景本身**\n- 文字、招牌上的可读文字、水印、签名\n- 动态模糊、运动中的物体（场景参考图必须静止稳定）\n- 只罗列陈设清单而不交代相对位置（空间结构必须连续、自洽）\n\n## 保存\n\n调用 `save_scene_final_prompt`：prompt 参数不含风格词，**项目视觉风格由工具自动注入到最终提示词的最前方**。\n\n<!-- File: backend/workspace/skills/prompt-generator/video-prompt/SKILL.md (Tokens: ~1809 | Category: anthropic-skill) -->\n---\nname: video-prompt\ndescription: 视频提示词规范 — 根据分镜段落内容生成按时间分段、段内可切镜的视频生成提示词\n---\n\n# 视频提示词（分镜段落 → video_prompt）\n\n根据单个分镜段落的 description（含【镜头N】子镜头结构与台词/旁白）/ atmosphere / duration，生成驱动 AI 视频生成的 `video_prompt`。**一个分镜段落 = 一段 8-15 秒的视频，内部允许切镜**：段与段之间可以是不同镜头（换景别/角度/对象），用硬切衔接；但**全程不跨场景**、不闪回。\n\n## 格式\n\n`video_prompt` 的**第一行是信息头**：先介绍这条视频有哪些人物和场景，然后再接时间分段。人物、场景一律用 @ 引用（生成时会替换为对应参考图片标记，让视频模型先对上\"谁\"和\"在哪\"）。\n\n```\n出场人物：@小明、@小红；场景：@咖啡厅。\n0-3秒：@咖啡厅，近景固定镜头，@小明低头看手机，手指反复敲桌面，表情焦虑。\n3-6秒：切到门口全景，门铃响，@小红推门走入，带进一阵冷风。\n6-9秒：切回中景，@小红微笑着走向小明坐下，小明说：「你终于来了。」\n```\n\n信息头规则：\n- 只列该分镜段落实际出场的人物和绑定的场景，不要列没出场的\n- 有明显道具出场时可在信息头追加（如 `；道具：@信件`）\n- 信息头独立一行，以句号结尾，之后是时间分段\n\n按 3 秒为一段，每段单独一行、用换行分隔，时间范围连续衔接（无重叠、无空缺）。\n\n## 与分镜描述的映射\n\n`description` 是 video_prompt 的唯一内容来源（画面、动作、台词、旁白都在其中），转换规则：\n\n- `description` 的每个 `【镜头N】` 映射为 **1-2 个连续的 3 秒段**，顺序一致、不遗漏、不合并、不新增子镜头\n- 台词/旁白从对应 `【镜头N】` 内的「角色名说：「…」」「旁白：…」提取，分配到该子镜头映射的段；**不要创作 description 之外的新台词**\n- 画面动作以 `description` 为准；`atmosphere` 只用于补各段的光线、色调与氛围描写\n\n## 段内结构\n\n每一段按此顺序组织内容（可省略无内容的项，但动作/画面必须有）：\n\n**时间范围 ＋ 场景@引用 ＋ 景别/运镜 ＋ 角色@引用＋主体动作·表情 ＋ 对白/旁白 ＋ 氛围光线**\n\n- **第一段必须建立空间**：场景 + 机位 + 角色的位置与状态，让观众一眼知道在哪、看谁\n- **切镜**：切镜后的段开头用\"切到/切回\"等衔接词，并重新交代景别与主体；切镜点应对齐分镜 `description` 中的 `【镜头N】` 结构\n- **景别/运镜**：每段一个镜头状态（近景/中景/全景/特写；固定/推/拉/摇/跟）；单个子镜头内运镜连续，切镜后可更换运镜方式\n- **动作**：每段一个主动作，动词具体可见（走、转身、抬头、攥紧、停顿）\n- **情绪全部转为可见描写**：不要\"他很伤心/气氛紧张\"这类抽象词，写成\"他低下头、手指攥紧杯沿、呼吸变重\"\n- **对白/旁白**：写「角色名说：「台词」」，旁白写「旁白：内容」；3 秒念不完的长台词拆到多段；无对白的段可写环境音/动作音（如\"机器持续轰鸣\"）\n\n## 引用规则\n\n- `@场景名` — 场景引用，名字必须与场景列表中的地点完全一致\n- `@角色名` — 角色引用，名字必须与角色列表中的名字完全一致\n- `@道具名` — 道具引用，名字必须与道具列表中的名字完全一致；道具在画面中明显可见、被使用或特写时引用\n- 生成时会自动把 `@名字` 替换为对应参考图片标记（如 `@小明` → `@图片1小明`），因此名字必须精确匹配，不要缩写或加额外符号\n- **每段至少一个 @ 引用锚定画面**；角色出场的段必须 @ 该角色；只引用该分镜段落已绑定的场景/角色/道具\n\n## 时间轴规则\n\n- 段数 = 分镜段落 duration ÷ 3 秒（向上取整），各段时间范围相加必须等于段落总时长\n- 内容节奏：第一段建立 → 中段推进动作/冲突 → 末段落到结果或情绪点\n\n## 禁止事项\n\n- 跨场景切换、闪回（一个段落只发生在一个场景内）\n- 引用列表之外的场景/角色名\n- 抽象心理描写、文学化比喻（模型只认可见画面）\n- 语言与会话语言指令不符\n\n## 保存\n\n调用 `update_storyboard` 仅更新该分镜段落的 `video_prompt` 字段，不要改动其他字段，不要重新拆分整集。\n\n<!-- File: backend/workspace/skills/script-rewriter/SKILL.md (Tokens: ~758 | Category: anthropic-skill) -->\n---\nname: script-rewriter\ndescription: 小说改写为格式化剧本的方法论和规范\n---\n\n# 剧本改写指南\n\n## 改写原则\n\n1. **保留核心情节**：不改变主线故事和角色关系\n2. **增强画面感**：将叙述性文字转化为可视化的场景描写\n3. **对话驱动**：用对白推动情节，减少旁白\n4. **节奏把控**：每场戏控制在 30-60 秒，适合短视频\n5. **不写镜头语言**：不涉及景别、角度、运镜，这些属于分镜拆解步骤\n\n## 格式化剧本格式\n\n```\n## S01 | 内景 · 咖啡厅 | 黄昏\n\n黄昏的光线透过落地窗洒进咖啡厅，吧台上咖啡杯热气升腾。\n\n小明独自坐在角落卡座，低头看手机，神情有些焦虑。\n\n门铃响起，小红推门而入。她看到小明，微笑着走过去。\n\n小红：（微笑）等很久了吗？\n小明：（抬头）还好，刚到。\n```\n\n### 格式规则\n\n- `## S编号 | 内景/外景 · 地点 | 时间段` — 场景头\n- 动作描写自然段 — 不包含任何镜头语言\n- `角色名：（状态/表情）台词内容` — 对白格式\n\n### 内容量参考\n\n格式化剧本相比原始内容增加约 20-30%，主要增量是场景头标记和对白格式化，不是扩写。\n\n## 改写步骤\n\n1. 先调用 `read_episode_script` 读取原始内容\n2. 分析内容结构（对话、叙述、心理描写的比例）\n3. 调用 `rewrite_to_screenplay` 执行改写\n4. 检查改写结果，确认符合格式化剧本格式\n5. 调用 `save_script` 保存最终结果\n\n## 注意事项\n\n- 心理描写可转化为角色表情/动作或画外音\n- 长段叙述拆分为多个短场景\n- 确保每个场景有明确的情绪转折点\n- 保持角色语言风格一致性\n- 场景编号连续递增（S01, S02, S03...）\n- 时间段要具体（黄昏、深夜、清晨），不要笼统写\"白天\"\n\n<!-- File: backend/workspace/skills/storyboard-breaker/SKILL.md (Tokens: ~1991 | Category: anthropic-skill) -->\n---\nname: storyboard-breaker\ndescription: 分镜拆解专业规范 — 将剧本拆分为可承载多个子镜头的分镜段落\n---\n\n# 分镜拆解指南\n\n## 核心定义：分镜段落\n\n一个分镜 = 一个 **分镜段落**（segment）= 一个视频生成任务。\n\n- 每个段落时长 **8-15 秒**，内部承载 **2-4 个子镜头**\n- 子镜头之间**可以切镜**：换景别、换角度、换拍摄对象，用硬切衔接\n- 子镜头之间**不跨场景**：一个段落只发生在一个场景内（`scene_id` 是段落级绑定）\n- 每个子镜头 2-6 秒，聚焦一个画面单元（一个动作、一个反应、一个特写）\n\n## 拆分流程（四步）\n\n1. 调用 `read_storyboard_context` 读取剧本、角色、场景、道具、已有分镜摘要\n2. **节拍识别**：先识别剧本的叙事节拍——剧本中的【开场】【触发】【高潮】【收尾】等标记，或叙事转折点（地点转移、规则揭示、情绪爆发、反转）。**节拍边界强制切段**，同一节拍内的子镜头优先归入同一段落，不把一条因果链（铺垫-发生-反应）切散到不同段落\n3. **总量锚定**：目标总时长 = 剧本字数 ÷ 500字/分钟；段落数 ≈ 目标总时长 ÷ 12秒，允许 ±20% 浮动。不要明显超出或不足\n4. **段落内拆子镜头**：按动作切换点、视角切换点、对象切换点切分子镜头，为每个段落补全完整字段后调用 `save_storyboards` 一次性保存\n\n## 节奏分层时长\n\n按段落功能确定时长，不要一刀切：\n\n| 段落类型 | 时长 | 说明 |\n|---|---|---|\n| 过渡段 | 8-10 秒 | 赶路、空镜、环境建立、转场 |\n| 叙事段 | 10-15 秒 | 常规剧情推进、对话 |\n| 爆点段 | 12-15 秒 | 特写、规则揭示、情感爆发、反转；子镜头节奏放慢，单个子镜头可停留 4-6 秒 |\n\n## 台词时长下限（硬规则）\n\n**段落时长 ≥ 段内台词与旁白总字数（写在 description 中的部分）÷ 4.5字/秒 + 2秒表演余量**\n\n装不下的台词必须拆到下一个段落，不允许把演不完的台词塞进一个段落。\n\n## 镜头要素\n\n1. **镜头标题**：3-5字概括段落核心内容（如\"噩梦惊醒\"）\n2. **时间**：具体时分 + 光线描述\n3. **地点**：场景完整描述 + 空间布局 + 环境细节\n4. **景别**：段落内主导景别；多景别段落写组合，如\"中景+特写\"\n5. **角度**：平视/仰视/俯视/侧面/背面\n6. **运镜**：固定/推镜/拉镜/摇镜/跟镜/移镜（段落内不同子镜头可不同）\n7. **画面描述** `description`：按 `【镜头1】…【镜头2】…` 逐子镜头描述观众实际看到和听到的内容——画面（谁 + 具体动作 + 肢体细节 + 表情）写在前；该子镜头有台词时以「角色名说：「台词」」写在对应 `【镜头N】` 内，旁白写「旁白：内容」\n8. **画面结果** `result`：段落结尾的即时后果 + 视觉细节\n9. **氛围** `atmosphere`：光线 + 色调 + 声音 + 整体氛围\n10. **时长** `duration`：段落总时长 8-15 秒，且满足台词时长下限\n11. **场景关联**：若能匹配已有场景，必须填写 `scene_id`\n12. **角色关联**：填写 `character_ids`，绑定当前段落涉及的 0 到多个角色\n13. **道具关联**：填写 `prop_ids`，绑定当前段落出现的关键道具（0 到多个）\n\n## 场景关联规则\n\n- 优先使用 `read_storyboard_context` 返回的 `scenes`\n- `location + time` 可明确匹配时，必须回填正确 `scene_id`\n- 不要凭空生成不存在的场景 ID\n- 如果剧本内容明显落在已有场景中，不要重复创造新场景描述\n\n## 角色绑定规则\n\n- `character_ids` 必须从 `read_storyboard_context` 返回的角色列表中选择\n- 一个段落可以没有角色，也可以绑定多个角色\n- 只要段落里有明确出场、被看见、发生动作或说话的角色，都应绑定进去\n- 纯环境段落、空镜、物件特写可以传空数组\n\n## 道具绑定规则\n\n- `prop_ids` 必须从 `read_storyboard_context` 返回的道具列表（`props`）中选择\n- 道具被角色使用、交接、特写，或在画面中明显可见且对叙事有意义时，必须绑定到该段落\n- 道具特写段落（无角色）也应绑定道具，`character_ids` 可为空\n- 与剧情无关的背景物品、场景陈设不要绑定；没有道具出现的段落传空数组\n- 绑定的道具会作为视频生成的参考图（白底单品图），保证道具外观跨段落一致\n\n## 质量要求\n\n- `description` 要适合人读，按子镜头详细描述观众实际看到和听到的内容；台词/旁白直接写在对应 `【镜头N】` 内\n- `image_prompt` 要突出单帧构图、角色外观、环境和光线（对应段落第一个子镜头）\n- `bgm_prompt` 和 `sound_effect` 用简洁短语即可，但不能空泛到只有“紧张”“悲伤”\n- 如需调整，调用 `update_storyboard` 修改具体段落\n\n<!-- File: CLAUDE.md (Tokens: ~1509 | Category: claude-rule) -->\n# CLAUDE.md\n\n## Project Overview\n\n火宝短剧（Huobao Drama）— AI 短剧/漫剧一站式制作工具。全 TypeScript 栈：小说 → 剧本改写 → 资产提取 → 生图 → 分镜拆解 → 生视频 → FFmpeg 拼接导出。支持 Electron 桌面版（macOS dmg）与服务器部署。\n\n## Structure\n\n```\nbackend/   — Hono + Drizzle ORM (better-sqlite3) + Mastra (AI agents)\nbackend/workspace/ — Agent 工作目录（Mastra Workspace jail 根）\nbackend/workspace/skills/ — Agent SKILL.md definitions（设置页可在线编辑）\nfrontend/  — Nuxt 3 + Vue 3 + TypeScript，ssr:false（纯 CSS，无 UI 框架）\ndesktop/   — Electron 桌面版：主进程 + esbuild 打包脚本 + electron-builder 配置\ndata/      — SQLite 数据库（huobao.sqlite3）+ 生成的静态文件（static/）\nconfigs/   — 遗留死配置，代码零引用\n```\n\n## Commands\n\n### Backend (`backend/`)\n- `npm run dev` — tsx watch 开发服务（端口 5679）\n- `npm start` — tsx 生产启动\n- `npm run typecheck` — TypeScript 类型检查\n- `npm run backfill-artwork` — 存量图片/视频补缩略图与海报帧\n\n### Frontend (`frontend/`)\n- `npm run dev` — Vite 开发服务（端口 3013，代理 /api 与 /static 到 5679）\n- `npm run generate` — 产出含 index.html 的静态站点（`.output/public`；`nuxt build` 不产 index.html，不能用于静态托管）\n\n### Desktop (`desktop/`，根目录 `npm run dist` 串联全流程)\n- `npm run dev` — 打包后端 bundle + Electron 窗口运行\n- `npm run build:backend` — esbuild 打包 backend/src → build/backend.mjs（ESM；externals: sharp/better-sqlite3/ffmpeg-static/ffprobe-static）\n- `npm run build:main` — 打包主进程 → dist/main.js\n- `npm run rebuild:native` — better-sqlite3 按 Electron ABI 重编（原生模块 ABI 变化后必须执行；postinstall 已自动做）\n- `npm run dist` — prepare-resources + electron-builder 出 arm64/x64 dmg → release/\n- `npm run dist:win` — 交叉打包 Windows NSIS 安装器（win-x64）；win 版 ffmpeg.exe 缓存在 build/win-bin/（缺失时脚本提示下载地址）\n\n## Architecture\n\n### Backend\n- **HTTP**: Hono（入口 `src/index.ts`），路由挂 `/api/v1`，`/static` 服务 DATA_ROOT，生产托管前端静态目录\n- **Database**: SQLite（better-sqlite3 + WAL），`SQLITE_PATH` 覆盖库文件位置；DDL 在 `src/db/sqlite-schema.ts`，启动时幂等重放；Drizzle 表定义 `src/db/schema.ts`（sqlite-core）\n- **路径锚点**: `src/utils/paths.ts` 统一解析 DATA_ROOT/STORAGE_ROOT；桌面版由 Electron 主进程注入 env（`HUOBAO_DATA_DIR`/`SQLITE_PATH`/`WORKSPACE_PATH`/`FRONTEND_DIST`/`FFMPEG_BIN`/`FFPROBE_BIN`），dev 走仓库相对路径默认值\n- **AI Agents**: Mastra，4 个 agent（script_rewriter / extractor / storyboard_breaker / prompt_generator），instructions 从 `workspace/prompts/*.md` + skills 动态拼接，模型按请求解析；fetch 补丁链适配国内中转站（关思考/温度/max_tokens）\n- **媒体生成**: `services/generation.ts` 统一任务生命周期（sys_task 表），适配器模式：图片 openai/gemini/volcengine，视频 volcengine/minimax\n- **视频拼接**: `services/ffmpeg-merge.ts`，FFmpeg 二进制内置（ffmpeg-static），可用 `FFMPEG_BIN`/`FFPROBE_BIN` 覆盖\n\n### Frontend\n- Nuxt 3 SPA，动态路由在 `nuxt.config.ts` 的 `pages:extend` 手动注册（views/drama/）\n- `app/composables/useApi.ts` 统一 fetch 客户端（全相对路径，生产与后端同源）\n- 核心工作台 `app/views/drama/episode.vue`（剧本→制作→导出流水线）\n\n### Desktop\n- 主进程 `desktop/src/main.ts`：单实例锁 → 空闲端口 → userData 准备（workspace 模板 copy-once + `.template-version` 版本标记）→ `utilityProcess.fork` 后端 → 轮询 health → BrowserWindow\n- userData：打包版 `~/Library/Application Support/HuobaoDrama/`，dev 版 `HuobaoDrama-Dev/`（互不干扰）\n- 后端 bundle 在 asar 内（externals 经 asar node_modules 解析，.node 自动重定向 unpacked）\n\n## Database\nSQLite 单文件（默认 `data/huobao.sqlite3`，桌面版在 userData）。启动时 `initSqliteSchema` 幂等建表 + 风格预设种子。MySQL→SQLite 一次性迁移：`cd backend && npx tsx scripts/import-mysql-to-sqlite.ts [--force]`（逐表行数校验、写前备份）。\n\n## Key Config\n- AI 服务配置存 DB（`ai_service_configs` 表），设置页维护，不在配置文件\n- 环境变量全集见 README「环境变量」；`configs/config.yaml` 是死配置（勿参考）\n- `PUBLIC_BASE_URL`：Seedance 引用本地参考资源需公网地址，桌面版无此能力（有中文报错）\n</yakaai_skills>"}