{
  "name": "VIVID v5.0 \u2014 Chapter Sub-workflow",
  "nodes": [
    {
      "id": "sub-trigger",
      "name": "Sub-workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1,
      "position": [
        200,
        400
      ],
      "parameters": {}
    },
    {
      "id": "node-02-rhubarb",
      "name": "Node 2 \u2014 Rhubarb Lipsync",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        480,
        260
      ],
      "parameters": {
        "command": "=rhubarb \"{{ $json.chapter_audio_path }}\" -f json -o \"{{ $json.project_root }}/lipsync/{{ $json.chapter_id }}_lipsync.json\"",
        "options": {}
      },
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000,
      "onError": "continueErrorOutput",
      "_comment": "BN-4: CPU \uc804\uc6a9 \u2014 GPU \uc791\uc5c5(Node 3/4)\uacfc \uc644\uc804 \ubcd1\ub82c. \ucc55\ud130\ubcc4 mp3 \uae30\ubc18 \ub9bd\uc2f1\ud06c \ubd84\uc11d."
    },
    {
      "id": "node-02-parse",
      "name": "Node 2 \u2014 Parse Lipsync",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        260
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const fs = require('fs');\nconst path = require('path');\nconst item = $input.first().json;\nconst lipsyncPath = path.join(item.project_root, 'lipsync', `${item.chapter_id}_lipsync.json`);\nif (!fs.existsSync(lipsyncPath)) {\n  return [{ json: { ...item, lipsync_path: null, lipsync_error: 'Rhubarb output missing' } }];\n}\nconst raw = JSON.parse(fs.readFileSync(lipsyncPath, 'utf-8'));\nconst speaking = [];\nconst cues = raw.mouthCues || [];\nlet segStart = null;\nfor (const c of cues) {\n  if (c.value !== 'X') {\n    if (segStart === null) segStart = c.start;\n  } else {\n    if (segStart !== null) { speaking.push({ start: segStart, end: c.start, mouth: 'speaking' }); segStart = null; }\n  }\n}\nif (segStart !== null) speaking.push({ start: segStart, end: cues[cues.length-1].end || segStart+0.1, mouth: 'speaking' });\nconst refined = path.join(item.project_root, 'lipsync', `${item.chapter_id}_lipsync.json`);\nfs.writeFileSync(refined, JSON.stringify(speaking, null, 2), 'utf-8');\nreturn [{ json: { ...item, lipsync_path: refined.replace(/\\\\/g, '/'), speaking_segments: speaking.length } }];"
      }
    },
    {
      "id": "node-03-director",
      "name": "Node 3 \u2014 Director (Gemini)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        540
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// n8n_workflow/nodes/node3_director_prompt.js \ub0b4\uc6a9 \ubd99\uc5ec\ub123\uae30.\n// \ub300\ubcf8 + SRT \u2192 Gemini CLI \u2192 \uc5f0\ucd9c \uae30\ud68d\uc548 JSON (camera_choreography, kinetic_typography \ub4f1).\n// \ucd9c\ub825: project/plan/<chapter_id>_plan.json \uc800\uc7a5 + plan_path \ubc18\ud658.\nthrow new Error('[Sub] node3_director_prompt.js \ucf54\ub4dc\ub97c \uc774 Code Node\uc5d0 \ubd99\uc5ec\ub123\uc73c\uc138\uc694.');"
      },
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 15000,
      "onError": "continueErrorOutput"
    },
    {
      "id": "node-04-asset-prompt",
      "name": "Node 4 \u2014 Asset Prompt (Gemini)",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        540
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// n8n_workflow/nodes/node4_asset_prompt.js \ub0b4\uc6a9 \ubd99\uc5ec\ub123\uae30.\n// Node 3 plan + references_catalog \u2192 Gemini CLI \u2192 asset_prompts[] \ubc30\uc5f4.\n// 5\uacc4\uce35 \uac80\uc0c9 + pose \ub77c\uc774\ube0c\ub7ec\ub9ac \ub9e4\uce6d + \uc2dc\ub4dc \uc815\ucc45.\nthrow new Error('[Sub] node4_asset_prompt.js \ucf54\ub4dc\ub97c \uc774 Code Node\uc5d0 \ubd99\uc5ec\ub123\uc73c\uc138\uc694.');"
      },
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 15000,
      "onError": "continueErrorOutput"
    },
    {
      "id": "node-05-split",
      "name": "Node 5 \u2014 Split Asset Items",
      "type": "n8n-nodes-base.itemLists",
      "typeVersion": 3,
      "position": [
        960,
        540
      ],
      "parameters": {
        "operation": "splitOutItems",
        "fieldToSplitOut": "asset_prompts",
        "options": {
          "include": "allOtherFields"
        }
      },
      "_comment": "1\ub300N \uc804\uac1c: \ubc30\uc5f4 asset_prompts\ub97c \uac1c\ubcc4 n8n \uc544\uc774\ud15c\uc73c\ub85c \ubd84\ud560. \uba54\ud0c0\ub370\uc774\ud130(chapter_id, scene_id \ub4f1) \uc720\uc9c0."
    },
    {
      "id": "node-02-34-merge",
      "name": "Merge \u2014 Rhubarb + Plan/Assets",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        960,
        400
      ],
      "parameters": {
        "mode": "combine",
        "combineBy": "combineByPosition"
      },
      "_comment": "Node 2(Rhubarb) + Node 3/4(Gemini \uae30\ud68d/\uc5d0\uc14b) \ubcd1\ub82c \ubd84\uae30 \ud569\ub958\uc810. lipsync_path\ub97c \uc5d0\uc14b \uc544\uc774\ud15c\ub4e4\uc5d0 \uc804\ud30c."
    },
    {
      "id": "node-06-switch",
      "name": "Node 6 \u2014 Asset Type Switch",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        1200,
        540
      ],
      "parameters": {
        "dataType": "string",
        "value1": "={{ $json.asset_type }}",
        "rules": {
          "rules": [
            {
              "value2": "character",
              "output": 0
            },
            {
              "value2": "prop",
              "output": 1
            },
            {
              "value2": "background",
              "output": 2
            },
            {
              "value2": "foreground",
              "output": 3
            }
          ]
        }
      },
      "_comment": "4\ubd84\uae30 \ub77c\uc6b0\ud305: character\u21927A, prop\u21927B, background\u21927C, foreground\u21927D"
    },
    {
      "id": "node-07-comfyui",
      "name": "Node 7 \u2014 ComfyUI Payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1440,
        540
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// n8n_workflow/nodes/node7_comfyui_payload.js \ub0b4\uc6a9 \ubd99\uc5ec\ub123\uae30.\n// L3 \uce90\uc2dc + 4\ubd84\uae30 \uc6cc\ud06c\ud50c\ub85c\uc6b0 \ube4c\ub354 + VRAM \uc815\ucc45.\n// ComfyUI API POST: http://127.0.0.1:8188/prompt\nthrow new Error('[Sub] node7_comfyui_payload.js \ucf54\ub4dc\ub97c \uc774 Code Node\uc5d0 \ubd99\uc5ec\ub123\uc73c\uc138\uc694.');"
      },
      "_comment": "Node 6 Switch\uc758 4\uac1c \ucd9c\ub825\uc774 \ubaa8\ub450 \uc774 \ub2e8\uc77c Code Node\ub85c \uc5f0\uacb0\ub428. asset_type \ud544\ub4dc\ub85c \ub0b4\ubd80 \ubd84\uae30."
    },
    {
      "id": "node-07-http",
      "name": "Node 7 \u2014 HTTP ComfyUI API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        1680,
        540
      ],
      "parameters": {
        "method": "POST",
        "url": "http://127.0.0.1:8188/prompt",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "client_id",
              "value": "={{ $json.prompt_id }}"
            },
            {
              "name": "prompt",
              "value": "={{ JSON.stringify($json.comfyui_payload?.prompt || {}) }}"
            }
          ]
        },
        "options": {
          "timeout": 300000
        }
      },
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 10000,
      "onError": "continueErrorOutput",
      "_comment": "skip_comfyui===true\uc778 \uce90\uc2dc \ud788\ud2b8 \uc544\uc774\ud15c\uc740 \uc774 \ub178\ub4dc\ub97c IF\ub85c \uc6b0\ud68c."
    },
    {
      "id": "node-07-cache-if",
      "name": "IF \u2014 Cache Hit Skip",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1560,
        400
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.skip_comfyui }}",
              "operation": "equals",
              "value2": true
            }
          ]
        }
      },
      "_comment": "L1/L2/L3 \uce90\uc2dc \ud788\ud2b8 \u2192 Node 8 \uc6f9\ud6c5 \ub300\uae30 \uc2a4\ud0b5, \ubc14\ub85c Node 9\ub85c."
    },
    {
      "id": "node-08-wait",
      "name": "Node 8 \u2014 Wait Webhook",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        1920,
        540
      ],
      "parameters": {
        "resume": "webhook",
        "options": {
          "webhookSuffix": "={{ $json.prompt_id }}",
          "timeout": 300,
          "timeoutUnit": "seconds"
        }
      },
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 10000,
      "_comment": "ComfyUI \uc644\ub8cc \uc6f9\ud6c5 \ub300\uae30. Resume Key = prompt_id. \ud0c0\uc784\uc544\uc6c3 300\ucd08."
    },
    {
      "id": "node-08-merge",
      "name": "Merge \u2014 Cache + Webhook",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        2160,
        470
      ],
      "parameters": {
        "mode": "append"
      },
      "_comment": "\uce90\uc2dc \ud788\ud2b8 \uacbd\ub85c + \uc6f9\ud6c5 \uc644\ub8cc \uacbd\ub85c \ud569\ub958"
    },
    {
      "id": "node-09-packager",
      "name": "Node 9 \u2014 Asset Packager",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2400,
        470
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// n8n_workflow/nodes/node9_asset_packager.js \ub0b4\uc6a9 \ubd99\uc5ec\ub123\uae30.\n// \ud30c\uc77c\uba85 \uaddc\uaca9\ud654 + WebP lossless \ubcc0\ud658 + \ud3f4\ub354 \uc815\ub9ac + \uc5d0\uc14b \uacbd\ub85c \ubaa9\ub85d JSON.\nthrow new Error('[Sub] node9_asset_packager.js \ucf54\ub4dc\ub97c \uc774 Code Node\uc5d0 \ubd99\uc5ec\ub123\uc73c\uc138\uc694.');"
      }
    },
    {
      "id": "node-09-5-archiver",
      "name": "Node 9.5 \u2014 Asset Archiver",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2640,
        470
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// n8n_workflow/nodes/node9_5_asset_archiver.js \ub0b4\uc6a9 \ubd99\uc5ec\ub123\uae30.\n// generate_asset:true \ud56d\ubaa9 \u2192 auto_generated_assets \uce74\ud0c8\ub85c\uadf8 \ub4f1\uc7ac + hnswlib \uc778\ub371\uc2a4.\nthrow new Error('[Sub] node9_5_asset_archiver.js \ucf54\ub4dc\ub97c \uc774 Code Node\uc5d0 \ubd99\uc5ec\ub123\uc73c\uc138\uc694.');"
      }
    },
    {
      "id": "node-10-assembler",
      "name": "Node 10 \u2014 Master Assembler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2880,
        470
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// n8n_workflow/nodes/node10_master_assembler.js \ub0b4\uc6a9 \ubd99\uc5ec\ub123\uae30.\n// plan + assets + lipsync + branding + delta \u2192 chapter_NN.html \ube4c\ub4dc.\nthrow new Error('[Sub] node10_master_assembler.js \ucf54\ub4dc\ub97c \uc774 Code Node\uc5d0 \ubd99\uc5ec\ub123\uc73c\uc138\uc694.');"
      }
    },
    {
      "id": "node-11-renderer",
      "name": "Node 11 \u2014 HyperFrames Render",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3120,
        470
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// n8n_workflow/nodes/node11_cinematic_renderer.js \ub0b4\uc6a9 \ubd99\uc5ec\ub123\uae30.\n// HyperFrames CLI \u2192 chapter_NN.mp4 \ub80c\ub354\ub9c1.\n// Stop & Resume: SHA256 \uce90\uc2dc \uac80\uc0ac \u2192 \ubcc0\uacbd \uc5c6\uc73c\uba74 \uc2a4\ud0b5.\nthrow new Error('[Sub] node11_cinematic_renderer.js \ucf54\ub4dc\ub97c \uc774 Code Node\uc5d0 \ubd99\uc5ec\ub123\uc73c\uc138\uc694.');"
      }
    },
    {
      "id": "sub-output",
      "name": "Sub-workflow Output",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        3360,
        470
      ],
      "parameters": {
        "mode": "manual",
        "duplicateItem": false,
        "assignments": {
          "assignments": [
            {
              "name": "concat_type",
              "value": "chapter",
              "type": "string"
            },
            {
              "name": "concat_path",
              "value": "={{ $json.render_mp4_path }}",
              "type": "string"
            },
            {
              "name": "chapter_id",
              "value": "={{ $json.chapter_id }}",
              "type": "string"
            },
            {
              "name": "chapter_index",
              "value": "={{ $json.chapter_index }}",
              "type": "number"
            },
            {
              "name": "chapter_global_start",
              "value": "={{ $json.chapter_global_start }}",
              "type": "number"
            },
            {
              "name": "chapter_global_end",
              "value": "={{ $json.chapter_global_end }}",
              "type": "number"
            },
            {
              "name": "duration_sec",
              "value": "={{ $json.duration_sec }}",
              "type": "number"
            }
          ]
        }
      },
      "_comment": "Master Workflow\uc758 Aggregate\ub85c \ubc18\ud658. concat_type + concat_path\ub85c Node 12\uac00 \uc21c\uc11c \uc870\ub9bd."
    },
    {
      "id": "sub-error-telegram",
      "name": "Error \u2014 Telegram Alert",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        2880,
        700
      ],
      "parameters": {
        "chatId": "={{ $env.TELEGRAM_CHAT_ID }}",
        "text": "\ud83d\udea8 Chapter Sub-workflow \uc2e4\ud328\n\n{{ $json.error_message || JSON.stringify($json) }}\n\n\ucc55\ud130: {{ $json.chapter_id || 'N/A' }}\n\uc2dc\uac04: {{ $now.toISO() }}",
        "additionalFields": {}
      }
    },
    {
      "id": "node-v5-api-route",
      "name": "IF \u2014 V5 API Route",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1640,
        260
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.source_api }}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "_comment": "V5.0: source_api\uac00 \uc788\uc73c\uba74 Pexels/Pixabay API \uacbd\ub85c, \uc5c6\uc73c\uba74 \uae30\uc874 \uce90\uc2dc \uc2a4\ud0b5 \uacbd\ub85c"
    },
    {
      "id": "node-v5-api-fetch",
      "name": "Node V5 \u2014 API Fetch & Result Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1880,
        160
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// n8n_workflow/nodes/node_v5_api_fetch.js \ub0b4\uc6a9 \ucc38\uc870\nthrow new Error('[Sub] node_v5_api_fetch.js \ucf54\ub4dc\ub97c \uc774 Code Node\uc5d0 \ubd99\uc5ec\ub123\uc73c\uc138\uc694.');"
      },
      "_comment": "V5.0: Pexels/Pixabay \ud638\ucd9c \ud6c4 \uc6d0\ubcf8 \ub370\uc774\ud130 \uc720\uc9c0\ud558\uba70 \ubcd1\ud569 (HTTP Request \ub36e\uc5b4\uc4f0\uae30 \ubc29\uc9c0)"
    }
  ],
  "connections": {
    "Sub-workflow Trigger": {
      "main": [
        [
          {
            "node": "Node 2 \u2014 Rhubarb Lipsync",
            "type": "main",
            "index": 0
          },
          {
            "node": "Node 3 \u2014 Director (Gemini)",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "_comment": "Node 2(Rhubarb CPU) + Node 3(Gemini) \ubcd1\ub82c \ubd84\uae30"
    },
    "Node 2 \u2014 Rhubarb Lipsync": {
      "main": [
        [
          {
            "node": "Node 2 \u2014 Parse Lipsync",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 2 \u2014 Parse Lipsync": {
      "main": [
        [
          {
            "node": "Merge \u2014 Rhubarb + Plan/Assets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 3 \u2014 Director (Gemini)": {
      "main": [
        [
          {
            "node": "Node 4 \u2014 Asset Prompt (Gemini)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 4 \u2014 Asset Prompt (Gemini)": {
      "main": [
        [
          {
            "node": "Merge \u2014 Rhubarb + Plan/Assets",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge \u2014 Rhubarb + Plan/Assets": {
      "main": [
        [
          {
            "node": "Node 5 \u2014 Split Asset Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 5 \u2014 Split Asset Items": {
      "main": [
        [
          {
            "node": "Node 6 \u2014 Asset Type Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 6 \u2014 Asset Type Switch": {
      "main": [
        [
          {
            "node": "Node 7 \u2014 ComfyUI Payload",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Node 7 \u2014 ComfyUI Payload",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Node 7 \u2014 ComfyUI Payload",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Node 7 \u2014 ComfyUI Payload",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "_comment": "4\ubd84\uae30 \ubaa8\ub450 \ub3d9\uc77c Node 7 Code Node\ub85c \uc218\ub834 \u2014 \ub0b4\ubd80\uc5d0\uc11c asset_type\uc73c\ub85c \ubd84\uae30"
    },
    "Node 7 \u2014 ComfyUI Payload": {
      "main": [
        [
          {
            "node": "IF \u2014 Cache Hit Skip",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF \u2014 Cache Hit Skip": {
      "main": [
        [
          {
            "node": "IF \u2014 V5 API Route",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Node 7 \u2014 HTTP ComfyUI API",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "_comment": "true(\uce90\uc2dc \ud788\ud2b8/API \uc2a4\ud0b5) \u2192 V5 API \ub77c\uc6b0\ud130, false(\uce90\uc2dc \ubbf8\uc2a4) \u2192 ComfyUI HTTP"
    },
    "IF \u2014 V5 API Route": {
      "main": [
        [
          {
            "node": "Node V5 \u2014 API Fetch & Result Handler",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge \u2014 Cache + Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "_comment": "true(source_api \uc788\uc74c) \u2192 API Fetch, false(\uae30\uc874 \uce90\uc2dc \uc2a4\ud0b5) \u2192 \ubc14\ub85c Merge"
    },
    "Node V5 \u2014 API Fetch & Result Handler": {
      "main": [
        [
          {
            "node": "Merge \u2014 Cache + Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 7 \u2014 HTTP ComfyUI API": {
      "main": [
        [
          {
            "node": "Node 8 \u2014 Wait Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 8 \u2014 Wait Webhook": {
      "main": [
        [
          {
            "node": "Merge \u2014 Cache + Webhook",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge \u2014 Cache + Webhook": {
      "main": [
        [
          {
            "node": "Node 9 \u2014 Asset Packager",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 9 \u2014 Asset Packager": {
      "main": [
        [
          {
            "node": "Node 9.5 \u2014 Asset Archiver",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 9.5 \u2014 Asset Archiver": {
      "main": [
        [
          {
            "node": "Node 10 \u2014 Master Assembler",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 10 \u2014 Master Assembler": {
      "main": [
        [
          {
            "node": "Node 11 \u2014 HyperFrames Render",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Node 11 \u2014 HyperFrames Render": {
      "main": [
        [
          {
            "node": "Sub-workflow Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true
  },
  "staticData": null,
  "id": "vivid-chapter-subworkflow-v45",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "tags": [
    {
      "name": "vivid"
    },
    {
      "name": "v4.5"
    },
    {
      "name": "sub-workflow"
    },
    {
      "name": "chapter"
    }
  ],
  "_vivid_meta": {
    "version": "5.0.0",
    "description": "Chapter Sub-workflow V5.0 \u2014 V4.5 \uae30\ubc18 + \uba40\ud2f0 \ud3ec\ub9f7 API \ub77c\uc6b0\ud305(Pexels/Pixabay) + solid_color \ud3f4\ubc31. Node 4\uac00 source_api \ud544\ub4dc\ub85c \ubd84\uae30, IF\u2192Switch\u2192HTTP\u2192Result Handler\u2192Merge \ub77c\uc6b0\ud305.",
    "pipeline_flow": "Trigger \u2192 [Node 2 Rhubarb \u2225 Node 3\u21924 Gemini] \u2192 Merge \u2192 Node 5 Split \u2192 Node 6 Switch(4\ubd84\uae30) \u2192 Node 7 Payload \u2192 IF(Cache) \u2192 [IF(API Route) \u2192 Switch(Pexels/Pixabay) \u2192 HTTP \u2192 Result Handler | HTTP ComfyUI \u2192 Wait] \u2192 Merge \u2192 Node 9 Packager \u2192 Node 9.5 Archiver \u2192 Node 10 Assembler \u2192 Node 11 Renderer \u2192 Output",
    "gpu_cpu_pipelining": {
      "strategy": "Master Workflow\uac00 Sub-workflow \ud050\ub97c \ubaa8\ub2c8\ud130\ub9c1\ud558\uc5ec N \ucc55\ud130 Node 11(CPU) + N+1 \ucc55\ud130 Node 7(GPU) \ub3d9\uc2dc \uc2e4\ud589",
      "constraint": "GPU \ub3d9\uc885 \ubcd1\ub82c \uae08\uc9c0 (VRAM 8.9GB \ud55c\uacc4). ComfyUI\ub294 \uc21c\ucc28 Batch size 1",
      "effect": "GPU \uc5d0\uc14b \uc0dd\uc131 + CPU \uc601\uc0c1 \ub80c\ub354\ub9c1 \uad50\ucc28\ub85c \ucd5c\uc18c 1\uc2dc\uac04 \ub2e8\ucd95"
    },
    "env_requirements": {
      "NODE_FUNCTION_ALLOW_BUILTIN": "*",
      "TELEGRAM_CHAT_ID": "\uc5d0\ub7ec \uc54c\ub9bc \uc218\uc2e0 Telegram \ucc44\ud305 ID",
      "PEXELS_API_KEY": "Pexels API \ud0a4 (V5.0 b_roll_video \ube44\ub514\uc624 \uac80\uc0c9\uc6a9)",
      "PIXABAY_API_KEY": "Pixabay API \ud0a4 (V5.0 real_photo \uc774\ubbf8\uc9c0 \uac80\uc0c9\uc6a9)"
    },
    "node_code_files": {
      "Node 3 \u2014 Director (Gemini)": "n8n_workflow/nodes/node3_director_prompt.js",
      "Node 4 \u2014 Asset Prompt (Gemini)": "n8n_workflow/nodes/node4_asset_prompt.js",
      "Node 7 \u2014 ComfyUI Payload": "n8n_workflow/nodes/node7_comfyui_payload.js",
      "Node 9 \u2014 Asset Packager": "n8n_workflow/nodes/node9_asset_packager.js",
      "Node 9.5 \u2014 Asset Archiver": "n8n_workflow/nodes/node9_5_asset_archiver.js",
      "Node 10 \u2014 Master Assembler": "n8n_workflow/nodes/node10_master_assembler.js",
      "Node 11 \u2014 HyperFrames Render": "n8n_workflow/nodes/node11_cinematic_renderer.js"
    }
  }
}