{
  "format": "mosael-workflow",
  "version": 1,
  "workflow_revision": 1,
  "name": "从主题到完整视频",
  "description": "输入一个主题，生成创意主旨、脚本和视觉圣经；角色和场景先到资产库里认，已有的直接用它的参考图，新出现的才画三视图 / 设定图并存成资产，按分镜自动搭 3D 白模并摆好每一镜的机位与运镜；再逐镜按白模画首帧（需要时加尾帧）或直接用三视图与白模运镜视频做参考生成视频，按顺序组装、配上口播字幕并导出。花费量级：默认最多 8 镜，每镜一次视频生成外加 1~2 张关键帧，另有最多 7 张角色三视图与场景设定图（库里已有的不再画）、5 次对话和逐镜配音——是所有模板里最贵的一条，开始节点的 max_shots 就是镜头数的上限，shot_seconds 是每镜几秒（建图时按所选视频模型取它能出的、最接近默认的那一档）。",
  "graph_hash": "1202e0711331970338889cde17c38125ebec730c3e16cd2898c4fcab1227ec11",
  "graph": {
    "meta": {
      "template_id": "full_video_generation",
      "template_version": 13,
      "source": "official"
    },
    "nodes": [
      {
        "id": "start",
        "type": "start",
        "name": "填写视频主题",
        "position": {
          "x": 40,
          "y": 300
        },
        "config": {
          "params": {
            "topic": "",
            "target_duration_seconds": 30,
            "shot_seconds": 5,
            "max_shots": 8,
            "audience": "对该主题感兴趣的大众观众",
            "tone": "专业、清晰、克制且有电影感",
            "language": "简体中文",
            "aspect_ratio": "16:9",
            "resolution": "720p",
            "fps": 30,
            "voice_id": ""
          },
          "required_params": [
            "topic"
          ]
        }
      },
      {
        "id": "frame_plan",
        "type": "json_extract",
        "name": "按画幅取尺寸",
        "position": {
          "x": 340,
          "y": -120
        },
        "config": {
          "source": "{\"16:9\": {\"frame_size\": \"\", \"video_size\": \"\", \"width\": 1920, \"height\": 1080}, \"9:16\": {\"frame_size\": \"\", \"video_size\": \"\", \"width\": 1080, \"height\": 1920}, \"1:1\": {\"frame_size\": \"\", \"video_size\": \"\", \"width\": 1080, \"height\": 1080}}",
          "path": "{{start.aspect_ratio}}"
        }
      },
      {
        "id": "creative_brief",
        "type": "llm",
        "name": "提炼核心主旨与创意简报",
        "position": {
          "x": 340,
          "y": 300
        },
        "config": {
          "profile_id": "",
          "model": "",
          "preset": "precise",
          "system": "你是资深创意总监和纪录片策划。先把用户给出的主题收敛为全片唯一核心主旨，\n建立清晰的受众收益、叙事因果和可执行视觉母题。不要编造未经输入支持的具体数字、引语、人物经历\n或研究结论；需要核实的内容写入 factual_boundaries。只输出符合 JSON Schema 的对象。",
          "prompt": "主题：{{start.topic}}\n目标时长：{{start.target_duration_seconds}} 秒\n目标观众：{{start.audience}}\n表达气质：{{start.tone}}\n成片语言：{{start.language}}\n\n请形成可直接供导演执行的创意简报。核心主旨只能有一个；若主题过宽，主动选择最有叙事张力且\n不需要虚构事实的角度。",
          "response_format": "json_schema",
          "json_schema_name": "professional_video_creative_brief",
          "json_schema": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "description": "准确、有记忆点且不过度承诺的视频标题"
              },
              "core_thesis": {
                "type": "string",
                "description": "全片唯一核心主旨，一句话可复述"
              },
              "audience_takeaway": {
                "type": "string",
                "description": "观众看完应理解、感受或采取的行动"
              },
              "opening_hook": {
                "type": "string",
                "description": "前五秒建立问题和观看理由的钩子"
              },
              "narrative_arc": {
                "type": "string",
                "description": "开场、展开、转折、收束的因果弧线"
              },
              "visual_concept": {
                "type": "string",
                "description": "贯穿全片的视觉母题与场景逻辑"
              },
              "tone": {
                "type": "string"
              },
              "factual_boundaries": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "不得凭空断言、需要用户复核的事实边界"
              }
            },
            "required": [
              "title",
              "core_thesis",
              "audience_takeaway",
              "opening_hook",
              "narrative_arc",
              "visual_concept",
              "tone",
              "factual_boundaries"
            ],
            "additionalProperties": false
          },
          "json_schema_strict": "true",
          "temperature": 0.3,
          "max_tokens": 2400
        }
      },
      {
        "id": "narrative_script",
        "type": "llm",
        "name": "编写叙事脚本与时间节拍",
        "position": {
          "x": 680,
          "y": 80
        },
        "config": {
          "profile_id": "",
          "model": "",
          "preset": "precise",
          "system": "你是资深编剧和旁白导演。围绕唯一核心主旨规划完整叙事，不引入创意简报之外\n的事实。按目标时长拆成首尾连续的叙事节拍：开头尽快建立观看理由，中段用因果而不是信息堆砌推进，\n结尾回收主旨。口播要自然、可说、符合指定语言。只输出符合 JSON Schema 的对象。",
          "prompt": "创意简报：\n{{creative_brief.text}}\n\n目标时长：{{start.target_duration_seconds}} 秒\n成片语言：{{start.language}}\n请输出完整口播，并把叙事拆成按时间连续的 beats。每个 beat 必须有明确叙事任务。",
          "response_format": "json_schema",
          "json_schema_name": "professional_video_narrative_script",
          "json_schema": {
            "type": "object",
            "properties": {
              "opening_hook": {
                "type": "string"
              },
              "narrative_arc": {
                "type": "string"
              },
              "full_narration": {
                "type": "string"
              },
              "beats": {
                "type": "array",
                "minItems": 1,
                "items": {
                  "type": "object",
                  "properties": {
                    "beat_number": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "start_seconds": {
                      "type": "number",
                      "minimum": 0
                    },
                    "end_seconds": {
                      "type": "number",
                      "exclusiveMinimum": 0
                    },
                    "objective": {
                      "type": "string",
                      "description": "这一段对主旨推进的唯一任务"
                    },
                    "narration": {
                      "type": "string",
                      "description": "该时间段的完整口播或对白"
                    }
                  },
                  "required": [
                    "beat_number",
                    "start_seconds",
                    "end_seconds",
                    "objective",
                    "narration"
                  ],
                  "additionalProperties": false
                }
              }
            },
            "required": [
              "opening_hook",
              "narrative_arc",
              "full_narration",
              "beats"
            ],
            "additionalProperties": false
          },
          "json_schema_strict": "true",
          "temperature": 0.4,
          "max_tokens": 5000
        }
      },
      {
        "id": "library_characters",
        "type": "entity_list",
        "name": "看看资产库里有哪些人物",
        "position": {
          "x": 340,
          "y": 620
        },
        "config": {
          "kind": "character"
        }
      },
      {
        "id": "library_locations",
        "type": "entity_list",
        "name": "看看资产库里有哪些场景",
        "position": {
          "x": 340,
          "y": 780
        },
        "config": {
          "kind": "location"
        }
      },
      {
        "id": "visual_bible",
        "type": "llm",
        "name": "定角色、场景与视觉圣经",
        "position": {
          "x": 680,
          "y": 520
        },
        "config": {
          "profile_id": "",
          "model": "",
          "preset": "creative",
          "system": "你是摄影指导、美术指导、角色设计和连续性监制。根据创意简报建立全片共享的视觉圣经：\n主体、环境、光线、色彩、镜头语言与连续性规则，规则要具体到生成模型可以复用，避免空泛风格词。\n同时定下**出镜角色**(最多 4 个；appearance 用英文写到能画出三视图的程度：年龄、脸型发型、服装与配色、\n体型、标志性道具)和**场景**(最多 3 个；description 用英文写空间、陈设、材质与光源，给出大致的\n长宽高)。每个角色分一个不同的白模颜色，并在 blockout_legend 里用英文说明颜色与角色的对应。\nstyle_prompt 是一句英文画风，全片每张图、每段视频都会带上。不得要求画面生成字幕、UI、Logo 或水印。\n用户会给出资产库里已有的人物和场景：故事需要的角色或场景**就是**其中某一个时，name 一字不差地沿用它的名字，\nappearance / description 照它的提示词描述写（它的参考图会直接拿来用，不再重画）；只是相像、并不是同一个的不要硬套，\n新建一个名字不同的。清单为空就全部新建。\n只输出符合 JSON Schema 的对象。",
          "prompt": "创意简报：\n{{creative_brief.text}}\n\n画幅：{{start.aspect_ratio}}；表达气质：{{start.tone}}。\n请建立整条视频共享的视觉圣经、摄影语言和跨镜头连续性规则，并定下出镜角色与场景。\n\n资产库里已有的人物（名字 — 提示词描述；空着就是还没有）：\n{{library_characters.text}}\n\n资产库里已有的场景：\n{{library_locations.text}}",
          "response_format": "json_schema",
          "json_schema_name": "professional_video_visual_bible",
          "json_schema": {
            "type": "object",
            "properties": {
              "subject_bible": {
                "type": "string",
                "description": "人物或主体跨镜头保持一致的外观与行为"
              },
              "environment_bible": {
                "type": "string",
                "description": "空间、时代、材质与关键道具约束"
              },
              "camera_language": {
                "type": "string",
                "description": "景别、焦段、机位与运镜的统一语法"
              },
              "lighting_plan": {
                "type": "string"
              },
              "color_palette": {
                "type": "string"
              },
              "continuity_rules": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "global_negative_prompt": {
                "type": "string"
              },
              "characters": {
                "type": "array",
                "maxItems": 4,
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^[a-z][a-z0-9-]{0,30}$",
                      "description": "英文小写短 id,如 hero"
                    },
                    "name": {
                      "type": "string"
                    },
                    "role": {
                      "type": "string",
                      "description": "在故事里是谁"
                    },
                    "appearance": {
                      "type": "string",
                      "description": "英文,交给图像模型画三视图:年龄、脸型发型、服装与配色、体型与身高、标志性道具"
                    },
                    "height_m": {
                      "type": "number",
                      "minimum": 0.5,
                      "maximum": 2.5
                    },
                    "blockout_color": {
                      "type": "string",
                      "enum": [
                        "#d9534f",
                        "#4a7fd6",
                        "#5cb85c",
                        "#e0a030"
                      ],
                      "description": "白模里这个人偶的颜色,每个角色不同"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "role",
                    "appearance",
                    "height_m",
                    "blockout_color"
                  ],
                  "additionalProperties": false
                },
                "description": "出镜的角色(最多 4 个);纯物件/风景的片子可以为空"
              },
              "locations": {
                "type": "array",
                "maxItems": 3,
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^[a-z][a-z0-9-]{0,30}$"
                    },
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string",
                      "description": "英文,交给图像模型画场景设定图:空间、时代、材质、关键陈设、光源"
                    },
                    "width_m": {
                      "type": "number",
                      "minimum": 2,
                      "maximum": 60
                    },
                    "depth_m": {
                      "type": "number",
                      "minimum": 2,
                      "maximum": 60
                    },
                    "height_m": {
                      "type": "number",
                      "minimum": 2,
                      "maximum": 20
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "description",
                    "width_m",
                    "depth_m",
                    "height_m"
                  ],
                  "additionalProperties": false
                },
                "description": "全片用到的场景(最多 3 个)"
              },
              "style_prompt": {
                "type": "string",
                "description": "英文一句话的全片画风,每张图、每段视频都会带上"
              },
              "blockout_legend": {
                "type": "string",
                "description": "英文,说明白模里各颜色人偶分别是谁,如 'red mannequin = Lin (class president), blue mannequin = Kai'"
              }
            },
            "required": [
              "subject_bible",
              "environment_bible",
              "camera_language",
              "lighting_plan",
              "color_palette",
              "continuity_rules",
              "global_negative_prompt",
              "characters",
              "locations",
              "style_prompt",
              "blockout_legend"
            ],
            "additionalProperties": false
          },
          "json_schema_strict": "true",
          "temperature": 0.55,
          "max_tokens": 5000
        }
      },
      {
        "id": "video_project",
        "type": "project_sequence_create",
        "name": "建立成片项目与时间线",
        "position": {
          "x": 1040,
          "y": -120
        },
        "config": {
          "name": "{{creative_brief.json.title}} · 自动成片",
          "width": "{{frame_plan.value.width}}",
          "height": "{{frame_plan.value.height}}",
          "fps": "{{start.fps}}"
        }
      },
      {
        "id": "character_sheets",
        "type": "loop_foreach",
        "name": "每个角色:库里有就用,没有就画三视图",
        "position": {
          "x": 1400,
          "y": 620
        },
        "config": {
          "items": "{{visual_bible.json.characters}}",
          "inputs": {
            "style": "{{visual_bible.json.style_prompt}}",
            "project_id": "{{video_project.project_id}}"
          },
          "body": {
            "nodes": [
              {
                "id": "find",
                "type": "entity_get",
                "name": "在资产库里找这个角色",
                "position": {
                  "x": 80,
                  "y": 140
                },
                "config": {
                  "kind": "character",
                  "name": "{{loop.item.name}}",
                  "limit": 1
                }
              },
              {
                "id": "has_art",
                "type": "condition",
                "name": "库里有它的图吗",
                "position": {
                  "x": 380,
                  "y": 140
                },
                "config": {
                  "left": "{{find.asset_ids.0}}",
                  "op": "not_empty"
                }
              },
              {
                "id": "sheet",
                "type": "ai_generate",
                "name": "画这个角色的三视图",
                "config": {
                  "provider": "",
                  "provider_profile_id": "",
                  "model": "",
                  "kind": "image",
                  "prompt": "Character turnaround reference sheet for {{loop.item.name}}: {{loop.item.appearance}}. Three full-body views of the same character side by side — front, side profile, back — identical outfit and proportions, relaxed A-pose, plain white background, soft even studio light, no text, no labels, no borders. {{input.style}}",
                  "parameters": {}
                },
                "position": {
                  "x": 680,
                  "y": 240
                }
              },
              {
                "id": "save",
                "type": "entity_save",
                "name": "存成人物资产",
                "config": {
                  "kind": "character",
                  "name": "{{loop.item.name}}",
                  "prompt": "{{loop.item.appearance}}",
                  "description": "{{loop.item.role}}",
                  "asset_ids": "",
                  "role": "turnaround"
                },
                "position": {
                  "x": 980,
                  "y": 240
                },
                "inputs": [
                  "asset_ids"
                ]
              },
              {
                "id": "file_art",
                "type": "asset_update",
                "name": "归档进成片项目",
                "position": {
                  "x": 980,
                  "y": 400
                },
                "config": {
                  "asset_ids": "",
                  "project_id": "{{input.project_id}}"
                },
                "inputs": [
                  "asset_ids"
                ]
              }
            ],
            "edges": [
              {
                "id": "find_check",
                "source": "find",
                "target": "has_art"
              },
              {
                "id": "missing_draw",
                "source": "has_art",
                "target": "sheet",
                "source_handle": "false"
              },
              {
                "id": "draw_save",
                "source": "sheet",
                "target": "save"
              },
              {
                "id": "draw_file",
                "source": "sheet",
                "target": "file_art"
              },
              {
                "id": "d-sheet-asset_id-save-asset_ids",
                "source": "sheet",
                "target": "save",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_ids"
              },
              {
                "id": "d-sheet-asset_id-file_art-asset_ids",
                "source": "sheet",
                "target": "file_art",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_ids"
              }
            ]
          },
          "output": "{{find.asset_ids.0}}{{sheet.asset_id}}:reference_image",
          "concurrency": 3
        }
      },
      {
        "id": "location_art",
        "type": "loop_foreach",
        "name": "每个场景:库里有就用,没有就画设定图",
        "position": {
          "x": 1400,
          "y": 820
        },
        "config": {
          "items": "{{visual_bible.json.locations}}",
          "inputs": {
            "style": "{{visual_bible.json.style_prompt}}",
            "project_id": "{{video_project.project_id}}"
          },
          "body": {
            "nodes": [
              {
                "id": "find",
                "type": "entity_get",
                "name": "在资产库里找这个场景",
                "position": {
                  "x": 80,
                  "y": 140
                },
                "config": {
                  "kind": "location",
                  "name": "{{loop.item.name}}",
                  "limit": 1
                }
              },
              {
                "id": "has_art",
                "type": "condition",
                "name": "库里有它的图吗",
                "position": {
                  "x": 380,
                  "y": 140
                },
                "config": {
                  "left": "{{find.asset_ids.0}}",
                  "op": "not_empty"
                }
              },
              {
                "id": "art",
                "type": "ai_generate",
                "name": "画这个场景的设定图",
                "config": {
                  "provider": "",
                  "provider_profile_id": "",
                  "model": "",
                  "kind": "image",
                  "prompt": "Establishing concept art of {{loop.item.name}}: {{loop.item.description}}. Wide view of the empty set, no people, no text. {{input.style}}",
                  "parameters": {}
                },
                "position": {
                  "x": 680,
                  "y": 240
                }
              },
              {
                "id": "save",
                "type": "entity_save",
                "name": "存成场景资产",
                "config": {
                  "kind": "location",
                  "name": "{{loop.item.name}}",
                  "prompt": "{{loop.item.description}}",
                  "asset_ids": "",
                  "role": "wide"
                },
                "position": {
                  "x": 980,
                  "y": 240
                },
                "inputs": [
                  "asset_ids"
                ]
              },
              {
                "id": "file_art",
                "type": "asset_update",
                "name": "归档进成片项目",
                "position": {
                  "x": 980,
                  "y": 400
                },
                "config": {
                  "asset_ids": "",
                  "project_id": "{{input.project_id}}"
                },
                "inputs": [
                  "asset_ids"
                ]
              }
            ],
            "edges": [
              {
                "id": "find_check",
                "source": "find",
                "target": "has_art"
              },
              {
                "id": "missing_draw",
                "source": "has_art",
                "target": "art",
                "source_handle": "false"
              },
              {
                "id": "draw_save",
                "source": "art",
                "target": "save"
              },
              {
                "id": "draw_file",
                "source": "art",
                "target": "file_art"
              },
              {
                "id": "d-art-asset_id-save-asset_ids",
                "source": "art",
                "target": "save",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_ids"
              },
              {
                "id": "d-art-asset_id-file_art-asset_ids",
                "source": "art",
                "target": "file_art",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_ids"
              }
            ]
          },
          "output": "{{find.asset_ids.0}}{{art.asset_id}}:reference_image",
          "concurrency": 3
        }
      },
      {
        "id": "storyboard",
        "type": "llm",
        "name": "按时间拆解分镜与机位",
        "position": {
          "x": 1040,
          "y": 140
        },
        "config": {
          "profile_id": "",
          "model": "",
          "preset": "creative",
          "system": "你是导演、摄影指导、分镜师和生成提示词工程师。把创意简报拆成连续的\n{{start.shot_seconds}} 秒镜头。每镜给出精确起止时间、口播、场景(location_id)、出镜角色、人物站位与走位、景别、\n机位角度、焦段(lens_mm)、运镜方式与路径、主体动作、光线、声音设计和连续性。所有镜头时间必须\n首尾相接，不重叠、不留空；首镜建立钩子，中段逐步升级信息，末镜完成主旨回收。每镜 narration 念出来\n不得超过 {{start.shot_seconds}} 秒：中文按每秒约 4 字、英文按每秒约 2.5 个词估算，宁短勿长；超出的部分会被加速压进\n这一镜，听起来会很赶。\n\n每镜选一条出片路径(reference_mode,可选:keyframes):keyframes 先按白模机位画首帧再生成,\n构图最稳,适合绝大多数镜头;references 把角色三视图、场景设定图和白模运镜视频直接交给视频模型,\n适合环绕、长距离跟拍这类首尾两帧说不清的复杂运镜。first_frame_prompt 用英文完整描述第一帧画面。\ngeneration_prompt 用英文写动作节拍、表演、环境变化与光影，主体动作必须能在 {{start.shot_seconds}} 秒内完成；\n**不要写机位参数**(机位会从白模自动算出来补上),画面中不要生成字幕、UI、Logo 或水印。\ntransition_in/out 是交付给后期查看的剪辑意图；本工作流自动合成阶段按时间顺序硬切。只输出符合\nJSON Schema 的对象。",
          "prompt": "请把叙事脚本与视觉圣经合并成可直接生成的专业时间分镜。\n\n创意简报：\n{{creative_brief.text}}\n\n叙事脚本与节拍：\n{{narrative_script.text}}\n\n视觉圣经(含角色与场景 id)：\n{{visual_bible.text}}\n\n成片目标时长：{{start.target_duration_seconds}} 秒；画幅：{{start.aspect_ratio}}；\n语言：{{start.language}}。每个镜头固定 {{start.shot_seconds}} 秒。镜头数 = 目标时长 ÷ {{start.shot_seconds}} 向上取整，\n但**最多 {{start.max_shots}} 镜**；两者冲突时以上限为准，把成片做短一点，\n**不要**为了凑满时长而缩短单镜时长——单镜时长是固定的 {{start.shot_seconds}} 秒。时间码从 0 开始连续编号。",
          "response_format": "json_schema",
          "json_schema_name": "professional_timed_storyboard",
          "json_schema": {
            "type": "object",
            "properties": {
              "total_duration_seconds": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "timeline_summary": {
                "type": "string"
              },
              "continuity_bible": {
                "type": "string",
                "description": "所有镜头共享的人物、场景、风格连续性约束"
              },
              "shots": {
                "type": "array",
                "minItems": 1,
                "maxItems": 24,
                "items": {
                  "type": "object",
                  "properties": {
                    "shot_number": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "start_seconds": {
                      "type": "number",
                      "minimum": 0
                    },
                    "end_seconds": {
                      "type": "number",
                      "exclusiveMinimum": 0
                    },
                    "duration_seconds": {
                      "type": "number",
                      "exclusiveMinimum": 0
                    },
                    "story_beat": {
                      "type": "string",
                      "description": "该镜头推进叙事的唯一任务"
                    },
                    "narration": {
                      "type": "string",
                      "description": "该时间段的口播或对白，念出来不超过 {{start.shot_seconds}} 秒；无则写空字符串"
                    },
                    "location_id": {
                      "type": "string",
                      "description": "视觉圣经里的场景 id"
                    },
                    "characters": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "这一镜出镜的角色 id"
                    },
                    "blocking": {
                      "type": "string",
                      "description": "人物站位与走位:谁在哪、朝向哪、从哪走到哪(米为单位的相对位置)"
                    },
                    "shot_size": {
                      "type": "string",
                      "enum": [
                        "extreme wide",
                        "wide",
                        "full",
                        "medium",
                        "medium close-up",
                        "close-up",
                        "extreme close-up"
                      ]
                    },
                    "camera_angle": {
                      "type": "string",
                      "enum": [
                        "eye level",
                        "high angle",
                        "low angle",
                        "overhead",
                        "dutch angle"
                      ]
                    },
                    "lens_mm": {
                      "type": "integer",
                      "minimum": 14,
                      "maximum": 200,
                      "description": "等效全画幅焦段"
                    },
                    "camera_movement": {
                      "type": "string",
                      "enum": [
                        "static",
                        "dolly in",
                        "dolly out",
                        "pan",
                        "tilt",
                        "tracking",
                        "orbit",
                        "crane up",
                        "crane down"
                      ]
                    },
                    "camera_path": {
                      "type": "string",
                      "description": "机位从哪里开始、沿什么路径、到哪里结束,起止构图各是什么"
                    },
                    "subject_action": {
                      "type": "string",
                      "description": "主体在 {{start.shot_seconds}} 秒内可完成的动作节拍"
                    },
                    "lighting": {
                      "type": "string"
                    },
                    "sound_design": {
                      "type": "string",
                      "description": "环境声、拟音、音乐节拍与静默点"
                    },
                    "transition_in": {
                      "type": "string"
                    },
                    "transition_out": {
                      "type": "string"
                    },
                    "continuity_notes": {
                      "type": "string",
                      "description": "人物、服装、空间、光向和运动连续性"
                    },
                    "reference_mode": {
                      "type": "string",
                      "enum": [
                        "keyframes"
                      ],
                      "description": "这一镜用哪条路出片:keyframes = 先按白模机位画首帧(需要时加尾帧)再生成视频,构图最稳;references = 直接把角色三视图、场景设定图和白模运镜视频交给视频模型,适合复杂运镜"
                    },
                    "first_frame_prompt": {
                      "type": "string",
                      "description": "英文,这一镜第一帧画面的完整描述(人物、动作、表情、环境、光线、画风),交给图像模型画首帧"
                    },
                    "generation_prompt": {
                      "type": "string",
                      "description": "英文,交给视频模型:主体动作节拍(须能在 {{start.shot_seconds}} 秒内完成)、表演、环境变化、光影;不要写机位参数(会从白模自动补上),不要要求字幕、UI、Logo 或水印"
                    },
                    "negative_prompt": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "shot_number",
                    "start_seconds",
                    "end_seconds",
                    "duration_seconds",
                    "story_beat",
                    "narration",
                    "location_id",
                    "characters",
                    "blocking",
                    "shot_size",
                    "camera_angle",
                    "lens_mm",
                    "camera_movement",
                    "camera_path",
                    "subject_action",
                    "lighting",
                    "sound_design",
                    "transition_in",
                    "transition_out",
                    "continuity_notes",
                    "reference_mode",
                    "first_frame_prompt",
                    "generation_prompt",
                    "negative_prompt"
                  ],
                  "additionalProperties": false
                }
              }
            },
            "required": [
              "total_duration_seconds",
              "timeline_summary",
              "continuity_bible",
              "shots"
            ],
            "additionalProperties": false
          },
          "json_schema_strict": "true",
          "temperature": 0.65,
          "max_tokens": 12000
        }
      },
      {
        "id": "props",
        "type": "scene_props",
        "name": "可用的 3D 道具",
        "position": {
          "x": 340,
          "y": 940
        },
        "config": {
          "model_ids": ""
        }
      },
      {
        "id": "set_design",
        "type": "llm",
        "name": "设计 3D 白模布景与机位",
        "position": {
          "x": 1400,
          "y": 300
        },
        "config": {
          "profile_id": "",
          "model": "",
          "preset": "precise",
          "system": "你是布景师兼摄影助理。按分镜给每个镜头搭一个 3D 白模布景台，并放好这一镜的相机。\n输出就是 3D 场景的数据格式，会被直接建成场景、渲出参考帧交给图像和视频模型 —— 它决定每一镜的构图。\n\n坐标约定：单位米，Y 朝上，地面 y=0；所有坐标都写**世界坐标**。\n\n**台距 D 由布景尺寸算出来,不是固定值。** 取视觉圣经里最大的那个场景的 width_m 与 depth_m 中较大的\n那个,加 8 米;若不足 12 米就按 12 米。第 n 镜(shot_number = n)的布景台整体放在 x = n*D 附近,\n台内每一个物体和这一镜相机的 position / target 都要把 x 加上 n*D。\n**不要用固定的 40 米**:三四米宽的卧室按 40 米排开,台与台之间会空出三十多米,整个白模散成一串\n看不清的小点;而六十米的大场景在 40 米台距下会直接和隔壁穿模。\n\n**每个布景台先出一个组。** kind=\"group\",id=\"bay-<n>\",name=\"镜头 <n> · <这一镜的场景名>\",\nposition 写 [0,0,0],parent_id 写空字符串;这一台里的**每一个**物体(room、陈设、figure、相机)\n都把 parent_id 写成 \"bay-<n>\"。组只为收纳,它在原点,所以**不改变任何坐标** —— 上面那条\"都写世界\n坐标\"照旧成立。没有组的话,八个台摊平就是七十多条重名的平铺列表。\n\n每个布景台：\n- 一个 room(parameters.width/depth/height 取视觉圣经里这个场景的尺寸，position 为 [n*D,0,0]，\n  门洞在前后墙正中；没有天花板)。室外场景用一块 plane 当地面、几块 box 当远景体块。\n- 关键陈设用 box / cylinder / table / stairs 概括(桌椅、柜子、门、树……)，尺寸按真实比例。\n- 这一镜出镜的每个角色一个 figure:parameters.height = 角色身高,width 0.4~0.5(肩宽),depth 0.22~0.28;\n  color 用视觉圣经里这个角色的 blockout_color;position 按分镜的站位;rotation[1] 是朝向(度)。\n  id 写成 \"<角色id>-<n>\"。\n- **能用真道具就别用方块拼。** 下面那份「可用的 3D 道具」清单里的东西是已经建好的真实模型:\n  kind=\"model\",model_id 写清单里那个 id,name 写道具名,position/rotation 照常摆。清单里给了\n  每件道具实测的长宽高,按它和 figure(人)的比例摆,不要再用 parameters 去\"设定\"它的尺寸\n  (模型自带尺寸,parameters 对它无效)。清单为空就全用基本体。\n- 物体的 target 写 [0,1,0]、fov 写 45、track 写空数组 —— 只有相机用得上它们;\n  非 model 的物体 model_id 写空字符串。\n\n每镜一台相机：kind=\"camera\",id=\"cam-<n>\";position 是起始机位,target 是起始看向点(一般是主体的胸口\n或眼睛高度 1.3~1.6 米),fov 是竖直视角,由焦段换算:fov = 2*atan(12/焦段毫米)(14mm≈81°,24mm≈53°,\n35mm≈38°,50mm≈27°,85mm≈16°,135mm≈10°)。机位高度按机位角度:平视 1.5~1.7 米,俯拍 2.5~4 米,\n仰拍 0.3~0.8 米。相机必须在房间内、不穿过任何物体,和主体的距离要让景别成立(特写约 0.6~1 米,\n中景 1.5~2.5 米,全景 3~5 米)。\n运镜写在相机的 track 上：static 不写 track;其余至少两档 {time:0,...} 和 {time:{{start.shot_seconds}},...}\n(position/target/fov 三项都写),推 = 沿视线靠近主体,拉 = 远离,摇 = 机位不动只转 target,\n跟 = 机位和 target 一起平移,环绕 = 绕主体转(可加中间一档),升降 = 机位上下移动。\n\nshots:每镜一条 {id:\"shot-<n>\", name:\"镜头 <n>\", duration:{{start.shot_seconds}}, aspect:画幅, easing:\"smooth\",\ncamera_id:\"cam-<n>\"}。lighting 按视觉圣经的光线方案给方位角(0=相机默认一侧,90=右侧,180=逆光)、\n高度角、强度(2~5)、色温和软硬;preset 写 \"custom\"。background 写 \"#20242c\",ambient 写 1.5。\n只输出符合 JSON Schema 的对象。",
          "prompt": "视觉圣经(角色身高与白模颜色、场景尺寸)：\n{{visual_bible.text}}\n\n分镜(每镜的场景、出镜角色、站位、景别、机位角度、焦段、运镜与路径)：\n{{storyboard.text}}\n\n可用的 3D 道具(kind=\"model\" 时 model_id 只能从这里选;尺寸是实测值)：\n{{props.catalog}}\n\n画幅：{{start.aspect_ratio}}。请给每个镜头搭一个布景台并放好相机。",
          "response_format": "json_schema",
          "json_schema_name": "blockout_scene",
          "json_schema": {
            "type": "object",
            "properties": {
              "objects": {
                "type": "array",
                "maxItems": 480,
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "pattern": "^[A-Za-z0-9_-]{1,64}$"
                    },
                    "name": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "group",
                        "room",
                        "box",
                        "cylinder",
                        "sphere",
                        "plane",
                        "stairs",
                        "table",
                        "figure",
                        "model",
                        "camera"
                      ]
                    },
                    "parent_id": {
                      "type": "string"
                    },
                    "position": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      },
                      "minItems": 3,
                      "maxItems": 3
                    },
                    "rotation": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      },
                      "minItems": 3,
                      "maxItems": 3
                    },
                    "model_id": {
                      "type": "string"
                    },
                    "entity_id": {
                      "type": "string"
                    },
                    "parameters": {
                      "type": "object",
                      "properties": {
                        "width": {
                          "type": "number",
                          "minimum": 0.01
                        },
                        "height": {
                          "type": "number",
                          "minimum": 0.01
                        },
                        "depth": {
                          "type": "number",
                          "minimum": 0.01
                        },
                        "radius": {
                          "type": "number",
                          "minimum": 0.01
                        },
                        "steps": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 64
                        }
                      },
                      "required": [
                        "width",
                        "height",
                        "depth",
                        "radius",
                        "steps"
                      ],
                      "additionalProperties": false
                    },
                    "color": {
                      "type": "string",
                      "pattern": "^#[0-9a-fA-F]{6}$"
                    },
                    "target": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      },
                      "minItems": 3,
                      "maxItems": 3
                    },
                    "fov": {
                      "type": "number",
                      "minimum": 10,
                      "maximum": 120
                    },
                    "track": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "time": {
                            "type": "number",
                            "minimum": 0
                          },
                          "position": {
                            "type": "array",
                            "items": {
                              "type": "number"
                            },
                            "minItems": 3,
                            "maxItems": 3
                          },
                          "target": {
                            "type": "array",
                            "items": {
                              "type": "number"
                            },
                            "minItems": 3,
                            "maxItems": 3
                          },
                          "fov": {
                            "type": "number",
                            "minimum": 10,
                            "maximum": 120
                          },
                          "rotation": {
                            "type": "array",
                            "items": {
                              "type": "number"
                            },
                            "minItems": 3,
                            "maxItems": 3
                          }
                        },
                        "required": [
                          "time",
                          "position",
                          "target",
                          "fov",
                          "rotation"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "kind",
                    "parent_id",
                    "position",
                    "rotation",
                    "model_id",
                    "entity_id",
                    "parameters",
                    "color",
                    "target",
                    "fov",
                    "track"
                  ],
                  "additionalProperties": false
                }
              },
              "shots": {
                "type": "array",
                "minItems": 1,
                "maxItems": 32,
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "duration": {
                      "type": "number",
                      "minimum": 0.1,
                      "maximum": 120
                    },
                    "aspect": {
                      "type": "string",
                      "enum": [
                        "16:9",
                        "9:16",
                        "1:1"
                      ]
                    },
                    "easing": {
                      "type": "string",
                      "enum": [
                        "smooth",
                        "linear"
                      ]
                    },
                    "camera_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "duration",
                    "aspect",
                    "easing",
                    "camera_id"
                  ],
                  "additionalProperties": false
                }
              },
              "lighting": {
                "type": "object",
                "properties": {
                  "preset": {
                    "type": "string",
                    "enum": [
                      "custom"
                    ]
                  },
                  "azimuth": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 359
                  },
                  "elevation": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 90
                  },
                  "intensity": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 20
                  },
                  "temperature": {
                    "type": "integer",
                    "minimum": 1500,
                    "maximum": 12000
                  },
                  "softness": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  }
                },
                "required": [
                  "preset",
                  "azimuth",
                  "elevation",
                  "intensity",
                  "temperature",
                  "softness"
                ],
                "additionalProperties": false
              },
              "background": {
                "type": "string",
                "pattern": "^#[0-9a-fA-F]{6}$"
              },
              "ambient": {
                "type": "number",
                "minimum": 0,
                "maximum": 10
              }
            },
            "required": [
              "objects",
              "shots",
              "lighting",
              "background",
              "ambient"
            ],
            "additionalProperties": false
          },
          "json_schema_strict": "true",
          "temperature": 0.2,
          "max_tokens": 16000
        }
      },
      {
        "id": "build_set",
        "type": "scene_create",
        "name": "搭建 3D 白模场景",
        "position": {
          "x": 1720,
          "y": 300
        },
        "config": {
          "name": "{{creative_brief.json.title}} · 白模",
          "layout": ""
        },
        "inputs": [
          "layout"
        ]
      },
      {
        "id": "generate_shots",
        "type": "loop_foreach",
        "name": "逐镜生成画面与口播",
        "position": {
          "x": 2080,
          "y": 460
        },
        "config": {
          "items": "{{storyboard.json.shots}}",
          "inputs": {
            "project_id": "{{video_project.project_id}}",
            "voice_id": "{{start.voice_id}}",
            "scene_id": "{{build_set.scene_id}}",
            "sheets": "{{character_sheets.results}}",
            "locations": "{{location_art.results}}",
            "style": "{{visual_bible.json.style_prompt}}",
            "legend": "{{visual_bible.json.blockout_legend}}",
            "frame_size": "{{frame_plan.value.frame_size}}",
            "video_size": "{{frame_plan.value.video_size}}",
            "aspect_ratio": "{{start.aspect_ratio}}",
            "resolution": "{{start.resolution}}",
            "shot_seconds": "{{start.shot_seconds}}"
          },
          "body": {
            "nodes": [
              {
                "id": "render_blockout",
                "type": "scene_render",
                "name": "渲染本镜白模参考",
                "position": {
                  "x": 80,
                  "y": 140
                },
                "config": {
                  "scene_id": "{{input.scene_id}}",
                  "shot_id": "shot-{{loop.item.shot_number}}",
                  "render": "both",
                  "project_id": "{{input.project_id}}"
                }
              },
              {
                "id": "is_keyframes",
                "type": "condition",
                "name": "这一镜走首尾帧吗",
                "position": {
                  "x": 390,
                  "y": 60
                },
                "config": {
                  "left": "{{loop.item.reference_mode}}",
                  "op": "equals",
                  "right": "keyframes"
                }
              },
              {
                "id": "paint_first_frame",
                "type": "ai_generate",
                "name": "按白模机位画首帧",
                "position": {
                  "x": 700,
                  "y": 60
                },
                "config": {
                  "provider": "",
                  "provider_profile_id": "",
                  "model": "",
                  "kind": "image",
                  "prompt": "{{loop.item.first_frame_prompt}} Reference images: the first one is a grey 3D blockout of this exact shot — match its camera angle, lens, framing, horizon line and the placement of the coloured mannequins exactly ({{input.legend}}); the mannequins are stand-ins, render them as the real characters. The character turnaround sheets fix each character's face, hair, outfit and proportions; the location concept art fixes the set. Only the characters described above appear. {{input.style}}",
                  "parameters": {
                    "size": "{{input.frame_size}}"
                  },
                  "source_assets": [
                    "{{render_blockout.first_frame_asset_id}}:reference_image",
                    "{{input.sheets}}",
                    "{{input.locations}}"
                  ]
                }
              },
              {
                "id": "file_keyframes",
                "type": "asset_update",
                "name": "归档本镜关键帧",
                "position": {
                  "x": 1010,
                  "y": -100
                },
                "config": {
                  "asset_ids": "{{paint_first_frame.asset_id}},{{paint_last_frame.asset_id}}",
                  "name": "镜头 {{loop.item.shot_number}} · 关键帧",
                  "project_id": "{{input.project_id}}"
                }
              },
              {
                "id": "needs_last_frame",
                "type": "condition",
                "name": "这一镜要尾帧吗",
                "position": {
                  "x": 1010,
                  "y": 60
                },
                "config": {
                  "left": "{{loop.item.last_frame_prompt}}",
                  "op": "not_empty"
                }
              },
              {
                "id": "paint_last_frame",
                "type": "ai_generate",
                "name": "按白模机位画尾帧",
                "position": {
                  "x": 1320,
                  "y": 60
                },
                "config": {
                  "provider": "",
                  "provider_profile_id": "",
                  "model": "",
                  "kind": "image",
                  "prompt": "{{loop.item.last_frame_prompt}} This is the last frame of the same shot whose first frame is the second reference image — keep characters, wardrobe, lighting and set continuous. Reference images: the first one is a grey 3D blockout of this exact shot — match its camera angle, lens, framing, horizon line and the placement of the coloured mannequins exactly ({{input.legend}}); the mannequins are stand-ins, render them as the real characters. The character turnaround sheets fix each character's face, hair, outfit and proportions; the location concept art fixes the set. Only the characters described above appear. {{input.style}}",
                  "parameters": {
                    "size": "{{input.frame_size}}"
                  },
                  "source_assets": [
                    "{{render_blockout.last_frame_asset_id}}:reference_image",
                    "{{paint_first_frame.asset_id}}:reference_image",
                    "{{input.sheets}}",
                    "{{input.locations}}"
                  ]
                }
              },
              {
                "id": "generate_clip",
                "type": "ai_generate",
                "name": "生成这一镜",
                "position": {
                  "x": 1320,
                  "y": 260
                },
                "config": {
                  "provider": "",
                  "provider_profile_id": "",
                  "model": "",
                  "kind": "video",
                  "prompt": "{{loop.item.generation_prompt}} Camera: {{render_blockout.camera_move}}. Keep every character exactly as in the references. {{input.style}}",
                  "negative_prompt": "{{loop.item.negative_prompt}}",
                  "parameters": {
                    "duration_seconds": "{{input.shot_seconds}}",
                    "aspect_ratio": "{{input.aspect_ratio}}",
                    "resolution": "{{input.resolution}}"
                  },
                  "source_assets": [
                    "{{paint_first_frame.asset_id}}:first_frame",
                    "{{paint_last_frame.asset_id}}:last_frame",
                    "{{input.sheets}}",
                    "{{input.locations}}",
                    "{{render_blockout.first_frame_asset_id}}:reference_image"
                  ],
                  "source_group": "{{loop.item.reference_mode}}"
                }
              },
              {
                "id": "organize_clip",
                "type": "asset_update",
                "name": "归档并命名镜头素材",
                "position": {
                  "x": 1630,
                  "y": 260
                },
                "config": {
                  "asset_ids": "",
                  "name": "镜头 {{loop.item.shot_number}}",
                  "project_id": "{{input.project_id}}"
                },
                "inputs": [
                  "asset_ids"
                ]
              },
              {
                "id": "has_voice",
                "type": "condition",
                "name": "选了配音音色吗",
                "position": {
                  "x": 80,
                  "y": 420
                },
                "config": {
                  "left": "{{input.voice_id}}",
                  "op": "not_empty"
                }
              },
              {
                "id": "has_narration",
                "type": "condition",
                "name": "这一镜有口播吗",
                "position": {
                  "x": 390,
                  "y": 420
                },
                "config": {
                  "left": "{{loop.item.narration}}",
                  "op": "not_empty"
                }
              },
              {
                "id": "narrate",
                "type": "synthesize_speech",
                "name": "合成该镜口播",
                "position": {
                  "x": 700,
                  "y": 420
                },
                "config": {
                  "text": "{{loop.item.narration}}",
                  "engine": "builtin:clone",
                  "voice": "{{input.voice_id}}"
                }
              }
            ],
            "edges": [
              {
                "id": "shot_blockout_mode",
                "source": "render_blockout",
                "target": "is_keyframes"
              },
              {
                "id": "shot_mode_first",
                "source": "is_keyframes",
                "target": "paint_first_frame",
                "source_handle": "true"
              },
              {
                "id": "shot_first_needs_last",
                "source": "paint_first_frame",
                "target": "needs_last_frame"
              },
              {
                "id": "shot_first_file",
                "source": "paint_first_frame",
                "target": "file_keyframes"
              },
              {
                "id": "shot_needs_last",
                "source": "needs_last_frame",
                "target": "paint_last_frame",
                "source_handle": "true"
              },
              {
                "id": "shot_blockout_generate",
                "source": "render_blockout",
                "target": "generate_clip"
              },
              {
                "id": "shot_generate_organize",
                "source": "generate_clip",
                "target": "organize_clip"
              },
              {
                "id": "shot_voice_gate_narration",
                "source": "has_voice",
                "target": "has_narration",
                "source_handle": "true"
              },
              {
                "id": "shot_narration_speak",
                "source": "has_narration",
                "target": "narrate",
                "source_handle": "true"
              },
              {
                "id": "d-generate_clip-asset_id-organize_clip-asset_ids",
                "source": "generate_clip",
                "target": "organize_clip",
                "kind": "data",
                "source_output": "asset_id",
                "target_input": "asset_ids"
              }
            ]
          },
          "output": "",
          "concurrency": 3,
          "max_items": "{{start.max_shots}}"
        }
      },
      {
        "id": "assemble_timeline",
        "type": "loop_foreach",
        "name": "按镜头顺序接上时间线",
        "position": {
          "x": 2400,
          "y": 460
        },
        "config": {
          "items": "",
          "inputs": {
            "sequence_id": "{{video_project.sequence_id}}",
            "video_track_id": "{{video_project.video_track_id}}",
            "audio_track_id": "{{video_project.audio_track_id}}",
            "shot_seconds": "{{start.shot_seconds}}"
          },
          "body": {
            "nodes": [
              {
                "id": "append_clip",
                "type": "timeline_append",
                "name": "按镜头顺序接入时间线",
                "position": {
                  "x": 80,
                  "y": 140
                },
                "config": {
                  "sequence_id": "{{input.sequence_id}}",
                  "asset_id": "{{loop.item.generate_clip.asset_id}}",
                  "track_id": "{{input.video_track_id}}",
                  "start": 0,
                  "end": "{{input.shot_seconds}}"
                }
              },
              {
                "id": "has_audio",
                "type": "condition",
                "name": "这一镜合成了口播吗",
                "position": {
                  "x": 390,
                  "y": 140
                },
                "config": {
                  "left": "{{loop.item.narrate.asset_id}}",
                  "op": "not_empty"
                }
              },
              {
                "id": "append_narration",
                "type": "timeline_append",
                "name": "把口播对齐到这一镜",
                "position": {
                  "x": 700,
                  "y": 140
                },
                "config": {
                  "sequence_id": "{{input.sequence_id}}",
                  "asset_id": "{{loop.item.narrate.asset_id}}",
                  "track_id": "{{input.audio_track_id}}",
                  "at": "",
                  "max_duration": ""
                },
                "inputs": [
                  "at",
                  "max_duration"
                ]
              },
              {
                "id": "caption",
                "type": "template",
                "name": "这一镜的字幕文本",
                "position": {
                  "x": 1010,
                  "y": 140
                },
                "config": {
                  "template": "{{loop.item.loop.item.narration}}"
                }
              }
            ],
            "edges": [
              {
                "id": "assemble_clip_gate",
                "source": "append_clip",
                "target": "has_audio"
              },
              {
                "id": "assemble_gate_narration",
                "source": "has_audio",
                "target": "append_narration",
                "source_handle": "true"
              },
              {
                "id": "assemble_narration_caption",
                "source": "append_narration",
                "target": "caption"
              },
              {
                "id": "d-append_clip-timeline_start-append_narration-at",
                "source": "append_clip",
                "target": "append_narration",
                "kind": "data",
                "source_output": "timeline_start",
                "target_input": "at"
              },
              {
                "id": "d-append_clip-duration-append_narration-max_duration",
                "source": "append_clip",
                "target": "append_narration",
                "kind": "data",
                "source_output": "duration",
                "target_input": "max_duration"
              }
            ]
          },
          "output": "",
          "concurrency": 1
        },
        "inputs": [
          "items"
        ]
      },
      {
        "id": "narration_subtitles",
        "type": "generate_subtitles",
        "name": "把口播做成字幕",
        "position": {
          "x": 2720,
          "y": 300
        },
        "config": {
          "sequence_id": "",
          "segments": "",
          "start_field": "append_narration.timeline_start",
          "end_field": "append_narration.timeline_end",
          "text_field": "caption.text",
          "allow_empty": "yes"
        },
        "inputs": [
          "sequence_id",
          "segments"
        ]
      },
      {
        "id": "export_final",
        "type": "export_sequence",
        "name": "合成并导出最终视频",
        "position": {
          "x": 3040,
          "y": 140
        },
        "config": {
          "sequence_id": ""
        },
        "inputs": [
          "sequence_id"
        ]
      },
      {
        "id": "done_notice",
        "type": "notify",
        "name": "成片完成通知",
        "position": {
          "x": 3360,
          "y": -40
        },
        "config": {
          "title": "视频已生成：{{creative_brief.json.title}}",
          "body": "脚本、角色三视图、3D 白模、各镜视频和最终合成均已完成。最终素材 ID：{{export_final.asset_id}}"
        }
      },
      {
        "id": "output",
        "type": "output",
        "name": "交付完整制作结果",
        "position": {
          "x": 3360,
          "y": 300
        },
        "config": {
          "values": {
            "title": "{{creative_brief.json.title}}",
            "core_thesis": "{{creative_brief.json.core_thesis}}",
            "creative_brief": "{{creative_brief.json}}",
            "narrative_script": "{{narrative_script.json}}",
            "visual_bible": "{{visual_bible.json}}",
            "storyboard": "{{storyboard.json}}",
            "character_sheets": "{{character_sheets.results}}",
            "location_art": "{{location_art.results}}",
            "blockout_scene_id": "{{build_set.scene_id}}",
            "shots": "{{generate_shots.results}}",
            "subtitle_count": "{{narration_subtitles.count}}",
            "project_id": "{{video_project.project_id}}",
            "sequence_id": "{{video_project.sequence_id}}",
            "final_asset_id": "{{export_final.asset_id}}"
          }
        }
      }
    ],
    "edges": [
      {
        "id": "start_brief",
        "source": "start",
        "target": "creative_brief"
      },
      {
        "id": "start_frame_plan",
        "source": "start",
        "target": "frame_plan"
      },
      {
        "id": "brief_narrative",
        "source": "creative_brief",
        "target": "narrative_script"
      },
      {
        "id": "brief_visual",
        "source": "creative_brief",
        "target": "visual_bible"
      },
      {
        "id": "start_library_characters",
        "source": "start",
        "target": "library_characters"
      },
      {
        "id": "start_library_locations",
        "source": "start",
        "target": "library_locations"
      },
      {
        "id": "library_characters_visual",
        "source": "library_characters",
        "target": "visual_bible"
      },
      {
        "id": "library_locations_visual",
        "source": "library_locations",
        "target": "visual_bible"
      },
      {
        "id": "start_props",
        "source": "start",
        "target": "props"
      },
      {
        "id": "props_set",
        "source": "props",
        "target": "set_design"
      },
      {
        "id": "visual_project",
        "source": "visual_bible",
        "target": "video_project"
      },
      {
        "id": "frame_plan_project",
        "source": "frame_plan",
        "target": "video_project"
      },
      {
        "id": "visual_sheets",
        "source": "visual_bible",
        "target": "character_sheets"
      },
      {
        "id": "visual_locations",
        "source": "visual_bible",
        "target": "location_art"
      },
      {
        "id": "project_sheets",
        "source": "video_project",
        "target": "character_sheets"
      },
      {
        "id": "project_locations",
        "source": "video_project",
        "target": "location_art"
      },
      {
        "id": "narrative_storyboard",
        "source": "narrative_script",
        "target": "storyboard"
      },
      {
        "id": "visual_storyboard",
        "source": "visual_bible",
        "target": "storyboard"
      },
      {
        "id": "storyboard_set",
        "source": "storyboard",
        "target": "set_design"
      },
      {
        "id": "set_build",
        "source": "set_design",
        "target": "build_set"
      },
      {
        "id": "build_generate",
        "source": "build_set",
        "target": "generate_shots"
      },
      {
        "id": "sheets_generate",
        "source": "character_sheets",
        "target": "generate_shots"
      },
      {
        "id": "locations_generate",
        "source": "location_art",
        "target": "generate_shots"
      },
      {
        "id": "generate_assemble",
        "source": "generate_shots",
        "target": "assemble_timeline"
      },
      {
        "id": "assemble_subtitles",
        "source": "assemble_timeline",
        "target": "narration_subtitles"
      },
      {
        "id": "subtitles_export",
        "source": "narration_subtitles",
        "target": "export_final"
      },
      {
        "id": "export_notice",
        "source": "export_final",
        "target": "done_notice"
      },
      {
        "id": "export_output",
        "source": "export_final",
        "target": "output"
      },
      {
        "id": "d-set_design-json-build_set-layout",
        "source": "set_design",
        "target": "build_set",
        "kind": "data",
        "source_output": "json",
        "target_input": "layout"
      },
      {
        "id": "d-generate_shots-results-assemble_timeline-items",
        "source": "generate_shots",
        "target": "assemble_timeline",
        "kind": "data",
        "source_output": "results",
        "target_input": "items"
      },
      {
        "id": "d-video_project-sequence_id-narration_subtitles-sequence_id",
        "source": "video_project",
        "target": "narration_subtitles",
        "kind": "data",
        "source_output": "sequence_id",
        "target_input": "sequence_id"
      },
      {
        "id": "d-assemble_timeline-results-narration_subtitles-segments",
        "source": "assemble_timeline",
        "target": "narration_subtitles",
        "kind": "data",
        "source_output": "results",
        "target_input": "segments"
      },
      {
        "id": "d-video_project-sequence_id-export_final-sequence_id",
        "source": "video_project",
        "target": "export_final",
        "kind": "data",
        "source_output": "sequence_id",
        "target_input": "sequence_id"
      }
    ]
  }
}
