ComfyUI Video Production Pipeline End-to-end video production orchestration for ComfyUI with automatic error recovery, quality validation, and instance management. Quick Start: Which Pipeline? Creating a multi-shot narrative video? → Keyframe Pipeline - Generate keyframes → Animate → Stitch with transitions Animating existing images? → I2V Batch Pipeline - Load images → Queue I2V jobs → Auto-validate → Combine Need smooth transitions between scenes? → Transition Pipeline - Crossfades, motion blur, zoom effects via FFmpeg ComfyUI stuck or crashed? → Instance Manager - Auto-restart, health chec…

\\n'\n fi\n fi\n done \u003c \"$yaml_file\"\n\n if [[ -n \"$current_id\" ]]; then\n ids+=(\"$current_id\")\n printf '%s' \"$current_prompt\" > \"$RESULTS_DIR/prompts/${current_id}.txt\"\n fi\n\n echo \"${ids[@]}\"\n}\n\nCASE_IDS=($(extract_cases))\necho \"Found ${#CASE_IDS[@]} test cases: ${CASE_IDS[*]}\"\n\nif [[ -n \"$SINGLE_CASE\" ]]; then\n CASE_IDS=(\"$SINGLE_CASE\")\n echo \"Filtering to: $SINGLE_CASE\"\nfi\necho \"\"\n\n# ─── Run test cases ────────────────────────────────────────────────\n\nrun_case() {\n local case_id=\"$1\"\n local mode=\"$2\"\n local prompt_file=\"$RESULTS_DIR/prompts/${case_id}.txt\"\n local output_file=\"$RESULTS_DIR/$mode/${case_id}.md\"\n local prompt_text\n prompt_text=$(cat \"$prompt_file\")\n\n echo \" [$mode] Running $case_id...\"\n\n if [[ \"$mode\" == \"with-skill\" ]]; then\n local full_prompt=\"Use the $SKILL_NAME skill to answer this: $prompt_text\"\n claude -p \"$full_prompt\" \\\n --allowedTools \"Read,Glob,Grep\" \\\n --max-turns 3 \\\n --output-format text \\\n > \"$output_file\" 2>/dev/null || {\n echo \"EVAL_ERROR: claude command failed for $case_id ($mode)\" > \"$output_file\"\n }\n else\n claude -p \"$prompt_text\" \\\n --allowedTools \"Read,Glob,Grep\" \\\n --max-turns 3 \\\n --output-format text \\\n > \"$output_file\" 2>/dev/null || {\n echo \"EVAL_ERROR: claude command failed for $case_id ($mode)\" > \"$output_file\"\n }\n fi\n\n local wc_out\n wc_out=$(wc -w \u003c \"$output_file\" | tr -d ' ')\n echo \" [$mode] $case_id complete ($wc_out words)\"\n}\n\nif ! $SCORE_ONLY; then\n if $RUN_SKILL; then\n echo \"── With Skill ──\"\n for case_id in \"${CASE_IDS[@]}\"; do\n run_case \"$case_id\" \"with-skill\"\n done\n echo \"\"\n fi\n\n if $RUN_BASELINE; then\n echo \"── Baseline (no skill) ──\"\n for case_id in \"${CASE_IDS[@]}\"; do\n run_case \"$case_id\" \"baseline\"\n done\n echo \"\"\n fi\nfi\n\n# ─── Assertion evaluation helpers ──────────────────────────────────\n\n# Extract first JSON block from response\nextract_json() {\n local text=\"$1\"\n # Try ```json fenced block first\n local block\n block=$(echo \"$text\" | sed -n '/```json/,/```/p' | sed '1d;$d')\n if [[ -z \"$block\" ]]; then\n # Try bare { ... } block\n block=$(echo \"$text\" | grep -Pzo '\\{[^{}]*(\\{[^{}]*\\}[^{}]*)*\\}' 2>/dev/null | head -1 || true)\n fi\n echo \"$block\"\n}\n\n# Get a field value from JSON (uses python if available, else node)\njson_field() {\n local json=\"$1\"\n local field=\"$2\"\n if command -v python3 &>/dev/null; then\n echo \"$json\" | python3 -c \"\nimport sys, json\ntry:\n d = json.load(sys.stdin)\n v = d.get('$field', '')\n if isinstance(v, list): print(len(v))\n elif isinstance(v, (int, float)): print(v)\n else: print(v)\nexcept: print('')\n\" 2>/dev/null\n elif command -v node &>/dev/null; then\n echo \"$json\" | node -e \"\nlet d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{\n try{const o=JSON.parse(d);const v=o['$field'];\n if(Array.isArray(v))console.log(v.length);\n else console.log(v??'');}catch(e){console.log('');}\n})\" 2>/dev/null\n else\n echo \"\"\n fi\n}\n\n# Word count of a string\nword_count() {\n echo \"$1\" | wc -w | tr -d ' '\n}\n\n# ─── Score a single assertion ──────────────────────────────────────\n\neval_assertion() {\n local response=\"$1\"\n local atype=\"$2\"\n local target=\"$3\"\n local json_block=\"$4\"\n\n case \"$atype\" in\n contains)\n echo \"$response\" | grep -qi \"$target\" && echo \"PASS\" || echo \"FAIL\"\n ;;\n\n not_contains)\n # Handle descriptive targets: if target contains spaces and \"should not contain\",\n # try to extract the quoted literal(s)\n if [[ \"$target\" =~ \\'([^\\']+)\\' ]]; then\n local found=false\n while [[ \"$target\" =~ \\'([^\\']+)\\' ]]; do\n local literal=\"${BASH_REMATCH[1]}\"\n if echo \"$response\" | grep -qi \"$literal\"; then\n found=true\n break\n fi\n target=\"${target#*\"'${literal}'\"}\"\n done\n $found && echo \"FAIL\" || echo \"PASS\"\n else\n echo \"$response\" | grep -qi \"$target\" && echo \"FAIL\" || echo \"PASS\"\n fi\n ;;\n\n regex)\n echo \"$response\" | grep -qiE \"$target\" && echo \"PASS\" || echo \"FAIL\"\n ;;\n\n question_before_code)\n local q_line code_line\n q_line=$(echo \"$response\" | grep -n '?' | head -1 | cut -d: -f1)\n code_line=$(echo \"$response\" | grep -n '```' | head -1 | cut -d: -f1)\n if [[ -z \"$code_line\" ]] || [[ -n \"$q_line\" && \"$q_line\" -lt \"$code_line\" ]]; then\n echo \"PASS\"\n else\n echo \"FAIL\"\n fi\n ;;\n\n json_valid)\n if [[ -n \"$json_block\" ]]; then\n if command -v python3 &>/dev/null; then\n echo \"$json_block\" | python3 -c \"import sys,json;json.load(sys.stdin)\" 2>/dev/null && echo \"PASS\" || echo \"FAIL\"\n elif command -v node &>/dev/null; then\n echo \"$json_block\" | node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{JSON.parse(d);console.log('PASS')}catch(e){console.log('FAIL')}})\" 2>/dev/null\n else\n echo \"SKIP\"\n fi\n else\n echo \"FAIL\"\n fi\n ;;\n\n json_schema|json_fields)\n # Target is comma-separated field names\n if [[ -z \"$json_block\" ]]; then\n echo \"FAIL\"\n return\n fi\n local all_found=true\n IFS=',' read -ra FIELDS \u003c\u003c\u003c \"$target\"\n for field in \"${FIELDS[@]}\"; do\n field=$(echo \"$field\" | xargs) # trim whitespace\n if ! echo \"$json_block\" | grep -q \"\\\"$field\\\"\"; then\n all_found=false\n break\n fi\n done\n $all_found && echo \"PASS\" || echo \"FAIL\"\n ;;\n\n token_limit)\n local wc\n wc=$(word_count \"$response\")\n local est_tokens=$(( wc * 13 / 10 ))\n [[ \"$est_tokens\" -le \"${target:-99999}\" ]] && echo \"PASS\" || echo \"FAIL\"\n ;;\n\n range_check)\n # Parse common patterns from the target expression\n if [[ -z \"$json_block\" ]]; then\n echo \"FAIL\"\n return\n fi\n\n # Handle: bias_score >= X AND bias_score \u003c= Y\n if [[ \"$target\" =~ ([a-z_]+)\\ *\\>=\\ *(-?[0-9.]+)\\ +AND\\ +\\1\\ *\\\u003c=\\ *(-?[0-9.]+) ]]; then\n local field=\"${BASH_REMATCH[1]}\"\n local min=\"${BASH_REMATCH[2]}\"\n local max=\"${BASH_REMATCH[3]}\"\n local val\n val=$(json_field \"$json_block\" \"$field\")\n if [[ -n \"$val\" ]] && command -v python3 &>/dev/null; then\n python3 -c \"v=$val; print('PASS' if $min \u003c= v \u003c= $max else 'FAIL')\" 2>/dev/null || echo \"FAIL\"\n else\n echo \"SKIP\"\n fi\n return\n fi\n\n # Handle: abs(field) \u003c= X\n if [[ \"$target\" =~ abs\\(([a-z_]+)\\)\\ *\\\u003c=\\ *(-?[0-9.]+) ]]; then\n local field=\"${BASH_REMATCH[1]}\"\n local limit=\"${BASH_REMATCH[2]}\"\n local val\n val=$(json_field \"$json_block\" \"$field\")\n if [[ -n \"$val\" ]] && command -v python3 &>/dev/null; then\n python3 -c \"v=$val; print('PASS' if abs(v) \u003c= $limit else 'FAIL')\" 2>/dev/null || echo \"FAIL\"\n else\n echo \"SKIP\"\n fi\n return\n fi\n\n # Handle: quality_score >= X\n if [[ \"$target\" =~ ([a-z_]+)\\ *\\>=\\ *(-?[0-9.]+)$ ]]; then\n local field=\"${BASH_REMATCH[1]}\"\n local min=\"${BASH_REMATCH[2]}\"\n local val\n val=$(json_field \"$json_block\" \"$field\")\n if [[ -n \"$val\" ]] && command -v python3 &>/dev/null; then\n python3 -c \"v=$val; print('PASS' if v >= $min else 'FAIL')\" 2>/dev/null || echo \"FAIL\"\n else\n echo \"SKIP\"\n fi\n return\n fi\n\n # Handle: len(field) >= X AND len(field) \u003c= Y (character length)\n if [[ \"$target\" =~ len\\(([a-z_]+)\\)\\ *\\>=\\ *([0-9]+)\\ +AND\\ +len\\(\\1\\)\\ *\\\u003c=\\ *([0-9]+) ]]; then\n local field=\"${BASH_REMATCH[1]}\"\n local min=\"${BASH_REMATCH[2]}\"\n local max=\"${BASH_REMATCH[3]}\"\n local val\n val=$(json_field \"$json_block\" \"$field\")\n local len=${#val}\n [[ \"$len\" -ge \"$min\" && \"$len\" -le \"$max\" ]] && echo \"PASS\" || echo \"FAIL\"\n return\n fi\n\n # Handle: len(field) \u003c= X\n if [[ \"$target\" =~ len\\(([a-z_]+)\\)\\ *\\\u003c=\\ *([0-9]+) ]]; then\n local field=\"${BASH_REMATCH[1]}\"\n local max=\"${BASH_REMATCH[2]}\"\n local val\n val=$(json_field \"$json_block\" \"$field\")\n local len=${#val}\n [[ \"$len\" -le \"$max\" ]] && echo \"PASS\" || echo \"FAIL\"\n return\n fi\n\n # Handle: len(field) >= X (list length)\n if [[ \"$target\" =~ len\\(([a-z_]+)\\)\\ *\\>=\\ *([0-9]+) ]]; then\n local field=\"${BASH_REMATCH[1]}\"\n local min=\"${BASH_REMATCH[2]}\"\n local val\n val=$(json_field \"$json_block\" \"$field\")\n [[ \"$val\" -ge \"$min\" ]] 2>/dev/null && echo \"PASS\" || echo \"FAIL\"\n return\n fi\n\n # Handle: word_count(field) >= X AND word_count(field) \u003c= Y\n if [[ \"$target\" =~ word_count\\(([a-z_]+)\\)\\ *\\>=\\ *([0-9]+)\\ +AND\\ +word_count\\(\\1\\)\\ *\\\u003c=\\ *([0-9]+) ]]; then\n local field=\"${BASH_REMATCH[1]}\"\n local min=\"${BASH_REMATCH[2]}\"\n local max=\"${BASH_REMATCH[3]}\"\n local val\n val=$(json_field \"$json_block\" \"$field\")\n local wc\n wc=$(word_count \"$val\")\n [[ \"$wc\" -ge \"$min\" && \"$wc\" -le \"$max\" ]] && echo \"PASS\" || echo \"FAIL\"\n return\n fi\n\n echo \"SKIP\" # Unrecognized expression\n ;;\n\n # Soft assertion types — logged but always PASS (require LLM judge)\n structure_check|sequence_check)\n echo \"SOFT\"\n ;;\n\n *)\n echo \"SKIP\"\n ;;\n esac\n}\n\n# ─── Score all assertions for a case ───────────────────────────────\n\nscore_case() {\n local case_id=\"$1\"\n local mode=\"$2\"\n local output_file=\"$RESULTS_DIR/$mode/${case_id}.md\"\n local score_file=\"$RESULTS_DIR/$mode/${case_id}.score.txt\"\n local response\n response=$(cat \"$output_file\" 2>/dev/null || echo \"\")\n\n if [[ \"$response\" == EVAL_ERROR* ]]; then\n echo \"ERROR\" > \"$score_file\"\n echo \"ERROR\"\n return\n fi\n\n local json_block\n json_block=$(extract_json \"$response\")\n\n local pass=0 fail=0 soft=0 skip=0 total=0\n local critical_fail=false\n local details=\"\"\n\n # Parse assertions from YAML\n local in_case=false\n local in_assertions=false\n local assert_type=\"\" assert_target=\"\" assert_critical=\"false\" assert_desc=\"\"\n\n process_assertion() {\n if [[ -z \"$assert_type\" ]]; then return; fi\n total=$((total + 1))\n local result\n result=$(eval_assertion \"$response\" \"$assert_type\" \"$assert_target\" \"$json_block\")\n\n case \"$result\" in\n PASS) pass=$((pass + 1)) ;;\n FAIL)\n fail=$((fail + 1))\n [[ \"$assert_critical\" == \"true\" ]] && critical_fail=true\n ;;\n SOFT) soft=$((soft + 1)) ;;\n SKIP) skip=$((skip + 1)) ;;\n esac\n\n local label=\"${assert_desc:-$assert_type($assert_target)}\"\n local crit_marker=\"\"\n [[ \"$assert_critical\" == \"true\" ]] && crit_marker=\" [CRITICAL]\"\n details+=\" $result$crit_marker — $label\"

ComfyUI Video Production Pipeline End-to-end video production orchestration for ComfyUI with automatic error recovery, quality validation, and instance management. Quick Start: Which Pipeline? Creating a multi-shot narrative video? → Keyframe Pipeline - Generate keyframes → Animate → Stitch with transitions Animating existing images? → I2V Batch Pipeline - Load images → Queue I2V jobs → Auto-validate → Combine Need smooth transitions between scenes? → Transition Pipeline - Crossfades, motion blur, zoom effects via FFmpeg ComfyUI stuck or crashed? → Instance Manager - Auto-restart, health chec…

\\n'\n }\n\n while IFS= read -r line; do\n if [[ \"$line\" =~ ^-\\ id:\\ $case_id$ ]]; then\n in_case=true\n continue\n fi\n if $in_case && [[ \"$line\" =~ ^-\\ id: ]]; then\n break\n fi\n\n if $in_case && [[ \"$line\" =~ ^\\ \\ \\ \\ -\\ type:\\ (.+) ]]; then\n process_assertion\n assert_type=\"${BASH_REMATCH[1]}\"\n assert_target=\"\"\n assert_critical=\"false\"\n assert_desc=\"\"\n fi\n if $in_case && [[ \"$line\" =~ ^\\ \\ \\ \\ \\ \\ target:\\ (.+) ]]; then\n assert_target=\"${BASH_REMATCH[1]}\"\n assert_target=\"${assert_target#\\\"}\"\n assert_target=\"${assert_target%\\\"}\"\n fi\n if $in_case && [[ \"$line\" =~ ^\\ \\ \\ \\ \\ \\ critical:\\ (.+) ]]; then\n assert_critical=\"${BASH_REMATCH[1]}\"\n fi\n if $in_case && [[ \"$line\" =~ ^\\ \\ \\ \\ \\ \\ description:\\ (.+) ]]; then\n assert_desc=\"${BASH_REMATCH[1]}\"\n assert_desc=\"${assert_desc#\\\"}\"\n assert_desc=\"${assert_desc%\\\"}\"\n fi\n done \u003c \"$SCRIPT_DIR/test-cases.yaml\"\n process_assertion # last assertion\n\n local anchored=$((pass + fail))\n local score_line=\"$pass/$total (${anchored} anchored, ${soft} soft, ${skip} skipped)\"\n if $critical_fail; then\n score_line+=\" [CRITICAL FAIL]\"\n fi\n\n {\n echo \"$score_line\"\n echo \"$details\"\n } > \"$score_file\"\n\n echo \"$score_line\"\n}\n\n# ─── Generate scorecard ───────────────────────────────────────────\n\ngenerate_scorecard() {\n local scorecard=\"$RESULTS_DIR/scorecard.md\"\n\n cat > \"$scorecard\" \u003c\u003cHEADER\n# Eval Scorecard — $SKILL_NAME\n**Timestamp:** $TIMESTAMP\n\n| Test Case | With Skill | Baseline |\n|-----------|-----------|----------|\nHEADER\n\n for case_id in \"${CASE_IDS[@]}\"; do\n local skill_score=\"—\"\n local base_score=\"—\"\n\n if $RUN_SKILL && [[ -f \"$RESULTS_DIR/with-skill/${case_id}.md\" ]]; then\n skill_score=$(score_case \"$case_id\" \"with-skill\")\n fi\n if $RUN_BASELINE && [[ -f \"$RESULTS_DIR/baseline/${case_id}.md\" ]]; then\n base_score=$(score_case \"$case_id\" \"baseline\")\n fi\n\n echo \"| $case_id | $skill_score | $base_score |\" >> \"$scorecard\"\n done\n\n echo \"\" >> \"$scorecard\"\n echo \"## Assertion Details\" >> \"$scorecard\"\n\n for case_id in \"${CASE_IDS[@]}\"; do\n echo \"\" >> \"$scorecard\"\n echo \"### $case_id\" >> \"$scorecard\"\n for mode in \"with-skill\" \"baseline\"; do\n if [[ -f \"$RESULTS_DIR/$mode/${case_id}.score.txt\" ]]; then\n echo \"**${mode}:**\" >> \"$scorecard\"\n echo '```' >> \"$scorecard\"\n cat \"$RESULTS_DIR/$mode/${case_id}.score.txt\" >> \"$scorecard\"\n echo '```' >> \"$scorecard\"\n fi\n done\n done\n\n echo \"\"\n echo \"=== Scorecard ===\"\n cat \"$scorecard\"\n}\n\ngenerate_scorecard\n\necho \"\"\necho \"=== Eval complete — $RESULTS_DIR/ ===\"\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":18242,"content_sha256":"4a5f64f9347e91d8bedb149ea5fd16263f0db37875164a5c584401f915567585"},{"filename":"eval/test-cases.yaml","content":"- id: TC-001\n name: simple-img2vid-pipeline\n prompt: \"I have a still image of a landscape and want to animate it into a 4-second video with gentle camera movement\"\n assertions:\n - type: regex\n target: \"(img2vid|image.to.video|I2V|still.to.video)\"\n description: \"Pipeline is img2vid\"\n critical: true\n - type: contains\n target: \"validation\"\n critical: true\n - type: regex\n target: \"(validate|check|verify|gate).*output\"\n description: \"Steps follow generate then validate then output pattern\"\n critical: false\n - type: regex\n target: \"(SVD|Stable Video|AnimateDiff|Wan|CogVideo)\"\n description: \"Appropriate model selected for img2vid\"\n critical: true\n expected_behavior: \"Produces an img2vid pipeline with proper step ordering, validation gates between stages, and appropriate model selection for still-to-video animation\"\n edge_case: false\n\n- id: TC-002\n name: error-recovery-seed-to-fallback\n prompt: \"Build a video generation pipeline that can handle failures gracefully — I'm generating product showcase videos and can't afford manual intervention\"\n assertions:\n - type: regex\n target: \"(seed|random).*((param|adjust|config)|(fallback|alternate))\"\n description: \"Retry strategy follows correct order: seed randomization then parameter adjustment then model fallback\"\n critical: true\n - type: not_contains\n target: \"retry with same parameters\"\n critical: true\n - type: regex\n target: \"(fallback|secondary|alternate|backup).*(model|checkpoint)\"\n description: \"Model fallback chain is defined\"\n critical: true\n - type: regex\n target: \"(retry|attempt|max|timeout|limit).*[0-9]\"\n description: \"Maximum retry count or timeout is specified\"\n critical: false\n expected_behavior: \"Defines a structured error recovery strategy with the correct escalation order: first randomize seed, then adjust parameters (steps, CFG, denoise), then fall back to alternate model. Never retries with identical parameters\"\n edge_case: false\n\n- id: TC-003\n name: multi-shot-video-with-transitions\n prompt: \"I need to produce a 30-second product video with 4 different shots: close-up, rotating view, lifestyle scene, and brand outro\"\n assertions:\n - type: regex\n target: \"(shot|scene|segment|stage).*[1-4]|(close.up|rotat|lifestyle|outro)\"\n description: \"Pipeline has separate generation stages for each shot\"\n critical: true\n - type: regex\n target: \"(each|every|per).*(validat|check|gate)\"\n description: \"Each shot has its own validation gate\"\n critical: true\n - type: regex\n target: \"(concat|merge|combin|assembl)\"\n description: \"Concatenation step comes after all shots\"\n critical: true\n - type: regex\n target: \"(consisten|style|lighting|color|uniform)\"\n description: \"Consistency strategy across shots\"\n critical: false\n expected_behavior: \"Plans a multi-shot pipeline where each shot is generated and validated independently before concatenation. Validation gates ensure each shot meets quality threshold before proceeding to assembly\"\n edge_case: false\n\n- id: TC-004\n name: validation-before-animation\n prompt: \"Create a txt2vid pipeline — generate a character and then animate them walking\"\n assertions:\n - type: regex\n target: \"(generat|image).*before.*(animat|video)\"\n description: \"Image generation happens before animation\"\n critical: true\n - type: regex\n target: \"(validat|check|gate).*(between|after.*generat)\"\n description: \"Validation check exists between image generation and animation step\"\n critical: true\n - type: structure_check\n target: \"Pipeline follows: generate image → validate image → animate → validate video → output\"\n description: \"Semantic check — requires understanding full pipeline ordering with all validation gates\"\n critical: true\n - type: not_contains\n target: \"generate and animate simultaneously\"\n critical: true\n expected_behavior: \"Strictly orders the pipeline: first generate the character image, then validate it passes quality checks, THEN animate. Does not skip the validation gate between generation and animation\"\n edge_case: true\n\n- id: TC-005\n name: vram-aware-pipeline-staging\n prompt: \"I have a 12GB GPU. Plan a video pipeline that generates 3 character clips and composites them together\"\n assertions:\n - type: regex\n target: \"(12\\\\s*GB|VRAM|memory|GPU)\"\n description: \"VRAM constraints acknowledged\"\n critical: true\n - type: regex\n target: \"(unload|free|release|clear).*(model|memory|VRAM)\"\n description: \"Model unloading between heavy stages is mentioned\"\n critical: true\n - type: regex\n target: \"(sequential|one.at.a.time|serial)\"\n description: \"Sequential rather than parallel generation given VRAM constraints\"\n critical: true\n - type: not_contains\n target: \"parallel generation\"\n description: \"Does not suggest parallel generation which would exceed VRAM\"\n critical: false\n - type: regex\n target: \"[0-9]+\\\\s*GB\"\n description: \"VRAM estimate per stage is provided\"\n critical: false\n expected_behavior: \"Recognizes 12GB VRAM as a constraint and plans sequential generation with model unloading between stages rather than attempting parallel generation that would OOM\"\n edge_case: false\n\n- id: TC-006\n name: audio-inclusive-video-pipeline\n prompt: \"I need a 15-second product showcase video with voiceover narration and background music. The narrator describes features while the product rotates.\"\n assertions:\n - type: regex\n target: \"(audio|voice|TTS|narrat|speech|sound)\"\n critical: true\n description: \"Must address the audio/voice component\"\n - type: regex\n target: \"(sync|align|timing|duration|match)\"\n critical: true\n description: \"Must address audio-video synchronization\"\n - type: regex\n target: \"(rotat|spin|turntable|orbit)\"\n critical: true\n description: \"Must address the rotation animation\"\n - type: contains\n target: \"validation\"\n critical: false\n expected_behavior: >\n Combines video generation with audio pipeline — TTS for voiceover,\n audio sync for timing, and multi-shot composition. The skill should\n plan the audio pipeline alongside video, not just focus on visuals.\n edge_case: false\n\n- id: TC-007\n name: comfyui-crash-recovery\n prompt: \"ComfyUI froze mid-generation on a 48-frame Wan video. The progress bar stopped at 60% and the GPU shows 100% utilization but nothing is happening. What do I do?\"\n assertions:\n - type: regex\n target: \"(kill|terminate|restart|stop|close|end process)\"\n critical: true\n description: \"Must advise how to recover the stuck process\"\n - type: regex\n target: \"(VRAM|memory|OOM|out of memory|GPU)\"\n critical: true\n description: \"Should diagnose likely cause (VRAM/OOM for 48 frames)\"\n - type: regex\n target: \"(reduce|fewer|shorter|lower|decrease).*(frame|step|resolution)\"\n critical: true\n description: \"Should suggest reducing frame count or resolution\"\n - type: regex\n target: \"(save|checkpoint|resume|recover)\"\n critical: false\n description: \"May suggest recovery strategies for partial progress\"\n expected_behavior: >\n 48 frames at high resolution likely caused an OOM that manifests as a\n GPU hang. The skill should diagnose this, advise recovery (kill process,\n clear VRAM), and suggest prevention (reduce frames, use tiling, lower\n resolution).\n edge_case: true\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":7621,"content_sha256":"77400fb1dcdb16e0b8b4e98c375e79ced3ff60fa006633e9f13d972a55a77305"},{"filename":"eval/trigger-tests.yaml","content":"should_trigger:\n - \"I need to create a video from a still image\"\n - \"Build a video generation pipeline with multiple shots\"\n - \"Help me set up a txt2vid workflow in ComfyUI\"\n - \"I want to animate my generated images into a product showcase video\"\n - \"Create a video pipeline that handles errors and retries automatically\"\n - \"Plan a multi-shot video production with consistent style across clips\"\n - \"I need to generate a 30-second video from text descriptions\"\n - \"Set up an img2vid pipeline with quality validation between steps\"\n - \"Help me orchestrate a video production workflow with AnimateDiff\"\n - \"I need a video pipeline that falls back to different models if generation fails\"\n\nshould_not_trigger:\n - \"Generate a single still image of a landscape\"\n - \"Help me write a prompt for an anime character\"\n - \"Build a ComfyUI workflow for text-to-image\"\n - \"How do I edit videos in DaVinci Resolve?\"\n - \"Explain how AnimateDiff works technically\"\n - \"Help me install video generation models\"\n - \"Review my ComfyUI workflow for performance\"\n - \"What's the best GPU for video generation?\"\n - \"Help me train a video model\"\n - \"Convert this video to a different format with ffmpeg\"\n\noptimized_description: >\n Plan and orchestrate end-to-end video production pipelines in ComfyUI with validation gates\n and error recovery. Handles img2vid, txt2vid, vid2vid, and multi-shot video production.\n Produces pipeline plans with correct step ordering (generate → validate → animate → validate →\n concat), model selection, retry strategies (seed randomization → parameter adjustment → model\n fallback), and VRAM-aware resource management. Does NOT cover still image generation, prompt\n writing, workflow building for non-video tasks, video editing in external tools, model\n training, installation, or hardware recommendations.\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":1855,"content_sha256":"e692637390fa9d7414a1bbd6e85c7507d3ebd00867b53450689d03529802c41d"},{"filename":"references/api-reference.md","content":"# ComfyUI API Reference\n\nComplete guide to ComfyUI's REST API for programmatic workflow submission and monitoring.\n\n---\n\n## Base URL\n\n```\nhttp://127.0.0.1:8188\n```\n\nFor multiple instances:\n- Primary: `http://127.0.0.1:8188`\n- Secondary: `http://127.0.0.1:8189`\n- Backup: `http://127.0.0.1:8190`\n\n---\n\n## Core Endpoints\n\n### GET /queue\n\nGet current queue status\n\n**Response:**\n```json\n{\n \"queue_running\": [\n [\"prompt_id\", 3, {\"prompt\": {...}, \"extra_data\": {...}}]\n ],\n \"queue_pending\": [\n [\"prompt_id\", 2, {\"prompt\": {...}, \"extra_data\": {...}}]\n ]\n}\n```\n\n### POST /prompt\n\nSubmit new workflow to queue\n\n**Request:**\n```json\n{\n \"prompt\": {\n \"1\": {\n \"class_type\": \"LoadImage\",\n \"inputs\": {\"image\": \"keyframe_01.png\"}\n },\n \"2\": {\n \"class_type\": \"UNETLoader\",\n \"inputs\": {\"unet_name\": \"wan2.2_14B.safetensors\"}\n }\n // ... more nodes\n },\n \"client_id\": \"optional_client_id\"\n}\n```\n\n**Response:**\n```json\n{\n \"prompt_id\": \"abc123-def456-ghi789\",\n \"number\": 42,\n \"node_errors\": {}\n}\n```\n\n### GET /history\n\nGet execution history\n\n**Response:**\n```json\n{\n \"prompt_id_1\": {\n \"prompt\": {...},\n \"outputs\": {\n \"14\": {\n \"images\": [\n {\n \"filename\": \"Sage_NSFW_Video_00001.mp4\",\n \"subfolder\": \"\",\n \"type\": \"output\"\n }\n ]\n }\n },\n \"status\": {\n \"status_str\": \"success\",\n \"completed\": true,\n \"messages\": []\n }\n }\n}\n```\n\n### GET /system_stats\n\nGet system information\n\n**Response:**\n```json\n{\n \"system\": {\n \"os\": \"nt\",\n \"python_version\": \"3.11.5\",\n \"embedded_python\": false\n },\n \"devices\": [\n {\n \"name\": \"NVIDIA GeForce RTX 5090\",\n \"type\": \"cuda\",\n \"index\": 0,\n \"vram_total\": 34359738368,\n \"vram_free\": 12884901888\n }\n ]\n}\n```\n\n### POST /free\n\nUnload models and free VRAM\n\n**Request:**\n```json\n{\n \"unload_models\": true,\n \"free_memory\": true\n}\n```\n\n### POST /interrupt\n\nInterrupt current execution\n\n**Request:** (empty or `{}`)\n\n---\n\n## Python API Client\n\n### Basic Client\n\n```python\nimport requests\nimport json\nimport time\n\nclass ComfyUIClient:\n def __init__(self, url=\"http://127.0.0.1:8188\"):\n self.url = url\n\n def submit_workflow(self, workflow):\n \"\"\"Submit workflow and return prompt_id\"\"\"\n data = json.dumps({\"prompt\": workflow})\n response = requests.post(\n f\"{self.url}/prompt\",\n data=data,\n headers={'Content-Type': 'application/json'}\n )\n return response.json()\n\n def get_queue(self):\n \"\"\"Get current queue status\"\"\"\n response = requests.get(f\"{self.url}/queue\")\n return response.json()\n\n def get_history(self, prompt_id=None):\n \"\"\"Get execution history\"\"\"\n url = f\"{self.url}/history\"\n if prompt_id:\n url += f\"/{prompt_id}\"\n response = requests.get(url)\n return response.json()\n\n def wait_for_completion(self, prompt_id, timeout=600, poll_interval=5):\n \"\"\"Wait for workflow to complete\"\"\"\n start = time.time()\n\n while time.time() - start \u003c timeout:\n history = self.get_history(prompt_id)\n\n if prompt_id in history:\n status = history[prompt_id].get('status', {})\n if status.get('completed'):\n return history[prompt_id]\n\n time.sleep(poll_interval)\n\n raise TimeoutError(f\"Workflow {prompt_id} did not complete in {timeout}s\")\n\n def get_output_files(self, prompt_id):\n \"\"\"Extract output files from completed workflow\"\"\"\n history = self.get_history(prompt_id)\n\n if prompt_id not in history:\n return []\n\n outputs = history[prompt_id].get('outputs', {})\n files = []\n\n for node_id, node_output in outputs.items():\n if 'images' in node_output:\n for image in node_output['images']:\n files.append({\n 'filename': image['filename'],\n 'subfolder': image.get('subfolder', ''),\n 'type': image['type']\n })\n\n return files\n\n def interrupt(self):\n \"\"\"Interrupt current execution\"\"\"\n response = requests.post(f\"{self.url}/interrupt\")\n return response.status_code == 200\n\n def free_memory(self):\n \"\"\"Unload models and free VRAM\"\"\"\n response = requests.post(\n f\"{self.url}/free\",\n json={\"unload_models\": True, \"free_memory\": True}\n )\n return response.status_code == 200\n```\n\n### Usage Example\n\n```python\n# Initialize client\nclient = ComfyUIClient(\"http://127.0.0.1:8188\")\n\n# Define workflow\nworkflow = {\n \"1\": {\n \"class_type\": \"LoadImage\",\n \"inputs\": {\"image\": \"keyframe_01.png\"}\n },\n \"2\": {\n \"class_type\": \"UNETLoader\",\n \"inputs\": {\"unet_name\": \"wan2.2_14B.safetensors\"}\n }\n # ... more nodes\n}\n\n# Submit\nresult = client.submit_workflow(workflow)\nprompt_id = result['prompt_id']\n\nprint(f\"Submitted: {prompt_id}\")\n\n# Wait for completion\ntry:\n completed = client.wait_for_completion(prompt_id, timeout=300)\n print(\"✓ Completed successfully\")\n\n # Get output files\n files = client.get_output_files(prompt_id)\n for f in files:\n print(f\"Output: {f['filename']}\")\n\nexcept TimeoutError:\n print(\"✗ Workflow timed out\")\n client.interrupt()\n```\n\n---\n\n## Batch Processing\n\n### Queue Multiple Workflows\n\n```python\ndef queue_batch(client, workflows, stagger_delay=2):\n \"\"\"\n Queue multiple workflows with staggered submission\n\n Args:\n client: ComfyUIClient instance\n workflows: List of workflow dicts\n stagger_delay: Seconds to wait between submissions\n\n Returns:\n List of prompt_ids\n \"\"\"\n prompt_ids = []\n\n for i, workflow in enumerate(workflows):\n print(f\"[Batch] Submitting {i+1}/{len(workflows)}...\")\n\n result = client.submit_workflow(workflow)\n prompt_id = result['prompt_id']\n prompt_ids.append(prompt_id)\n\n if i \u003c len(workflows) - 1: # Don't wait after last one\n time.sleep(stagger_delay)\n\n return prompt_ids\n\ndef wait_for_batch(client, prompt_ids, timeout=600):\n \"\"\"\n Wait for all workflows in batch to complete\n\n Args:\n client: ComfyUIClient instance\n prompt_ids: List of prompt IDs\n timeout: Max wait time per workflow\n\n Returns:\n Dict of {prompt_id: result}\n \"\"\"\n results = {}\n\n for prompt_id in prompt_ids:\n print(f\"[Batch] Waiting for {prompt_id}...\")\n\n try:\n result = client.wait_for_completion(prompt_id, timeout)\n results[prompt_id] = result\n print(f\"[Batch] ✓ {prompt_id} completed\")\n except TimeoutError:\n print(f\"[Batch] ✗ {prompt_id} timed out\")\n results[prompt_id] = None\n\n return results\n\n# Example usage\nkeyframes = [\n \"keyframe_01.png\",\n \"keyframe_02.png\",\n \"keyframe_03.png\",\n \"keyframe_04.png\",\n \"keyframe_05.png\"\n]\n\nworkflows = [\n create_i2v_workflow(kf, motion_prompt)\n for kf, motion_prompt in zip(keyframes, motion_prompts)\n]\n\n# Submit batch\nclient = ComfyUIClient()\nprompt_ids = queue_batch(client, workflows, stagger_delay=3)\n\n# Wait for all\nresults = wait_for_batch(client, prompt_ids, timeout=300)\n\n# Check success rate\ncompleted = sum(1 for r in results.values() if r is not None)\nprint(f\"\\n[Batch] {completed}/{len(results)} workflows completed\")\n```\n\n---\n\n## Advanced: WebSocket Monitoring\n\nFor real-time progress updates, use WebSocket connection:\n\n```python\nimport websocket\nimport json\nimport threading\n\nclass ComfyUIWebSocketMonitor:\n def __init__(self, url=\"ws://127.0.0.1:8188/ws\"):\n self.url = url\n self.ws = None\n self.callbacks = {}\n\n def on_message(self, ws, message):\n \"\"\"Handle incoming messages\"\"\"\n data = json.loads(message)\n\n msg_type = data.get('type')\n if msg_type in self.callbacks:\n self.callbacks[msg_type](data)\n\n def on_error(self, ws, error):\n print(f\"[WebSocket] Error: {error}\")\n\n def on_close(self, ws, close_status_code, close_msg):\n print(\"[WebSocket] Connection closed\")\n\n def register_callback(self, message_type, callback):\n \"\"\"Register callback for message type\"\"\"\n self.callbacks[message_type] = callback\n\n def connect(self):\n \"\"\"Connect to WebSocket\"\"\"\n self.ws = websocket.WebSocketApp(\n self.url,\n on_message=self.on_message,\n on_error=self.on_error,\n on_close=self.on_close\n )\n\n # Run in background thread\n thread = threading.Thread(target=self.ws.run_forever)\n thread.daemon = True\n thread.start()\n\n def disconnect(self):\n \"\"\"Disconnect from WebSocket\"\"\"\n if self.ws:\n self.ws.close()\n\n# Example usage\nmonitor = ComfyUIWebSocketMonitor()\n\ndef on_progress(data):\n \"\"\"Called when progress updates received\"\"\"\n value = data.get('data', {}).get('value', 0)\n max_val = data.get('data', {}).get('max', 100)\n print(f\"Progress: {value}/{max_val} ({value/max_val*100:.1f}%)\")\n\ndef on_execution_start(data):\n prompt_id = data.get('data', {}).get('prompt_id')\n print(f\"Execution started: {prompt_id}\")\n\ndef on_execution_complete(data):\n prompt_id = data.get('data', {}).get('prompt_id')\n print(f\"Execution completed: {prompt_id}\")\n\nmonitor.register_callback('progress', on_progress)\nmonitor.register_callback('execution_start', on_execution_start)\nmonitor.register_callback('executed', on_execution_complete)\n\nmonitor.connect()\n\n# Submit workflows...\n# Real-time progress will be printed\n\n# When done\nmonitor.disconnect()\n```\n\n---\n\n## Error Handling\n\n### Workflow Validation\n\n```python\ndef validate_workflow(workflow):\n \"\"\"Basic workflow validation before submission\"\"\"\n errors = []\n\n # Check required structure\n if not isinstance(workflow, dict):\n errors.append(\"Workflow must be a dictionary\")\n return errors\n\n # Check each node\n for node_id, node in workflow.items():\n if 'class_type' not in node:\n errors.append(f\"Node {node_id}: Missing class_type\")\n\n if 'inputs' not in node:\n errors.append(f\"Node {node_id}: Missing inputs\")\n\n return errors\n\n# Example usage\nerrors = validate_workflow(workflow)\nif errors:\n print(\"Workflow validation failed:\")\n for error in errors:\n print(f\" - {error}\")\nelse:\n # Submit workflow\n client.submit_workflow(workflow)\n```\n\n### Retry Logic\n\n```python\ndef submit_with_retry(client, workflow, max_retries=3):\n \"\"\"Submit workflow with automatic retry on failure\"\"\"\n for attempt in range(max_retries):\n try:\n result = client.submit_workflow(workflow)\n return result\n except Exception as e:\n print(f\"Attempt {attempt+1} failed: {e}\")\n if attempt \u003c max_retries - 1:\n time.sleep(5) # Wait before retry\n else:\n raise\n\n# Example usage\ntry:\n result = submit_with_retry(client, workflow, max_retries=3)\n print(f\"Submitted: {result['prompt_id']}\")\nexcept Exception as e:\n print(f\"Failed after 3 attempts: {e}\")\n```\n\n---\n\n## Best Practices\n\n1. **Always validate workflows** before submission\n2. **Use timeouts** when waiting for completion\n3. **Implement retry logic** for transient failures\n4. **Monitor queue depth** to avoid overload\n5. **Free memory** between large batches\n6. **Use WebSocket** for real-time progress tracking\n7. **Handle errors gracefully** with fallback strategies\n8. **Stagger batch submissions** to avoid overwhelming the server\n\n---\n\n## Common Issues\n\n### Issue: Connection refused\n**Cause:** ComfyUI not running or wrong port\n**Fix:** Check if ComfyUI is running on expected port\n\n### Issue: Workflow validation errors\n**Cause:** Invalid node inputs or missing required fields\n**Fix:** Validate workflow structure before submission\n\n### Issue: Timeout waiting for completion\n**Cause:** Workflow taking too long or stuck\n**Fix:** Increase timeout or use interrupt endpoint\n\n### Issue: Queue depth growing\n**Cause:** Submitting faster than processing\n**Fix:** Implement backpressure - check queue before submitting\n\n### Issue: VRAM out of memory\n**Cause:** Models not unloading between workflows\n**Fix:** Call `/free` endpoint periodically\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":12426,"content_sha256":"b16d9d601e395dcb6bf53c210f8ee6aa6549d26b7f75395420cce2cb58ec7206"},{"filename":"references/concatenation.md","content":"# Video Concatenation & Transitions\n\nProfessional video stitching with FFmpeg, including transition effects, audio handling, and quality preservation.\n\n---\n\n## Basic Concatenation\n\n### Method 1: FFmpeg Concat Demuxer (Recommended)\n\n**Use when:** All clips have same codec, resolution, FPS\n\n```bash\n# 1. Create concat list file\ncat > concat_list.txt \u003c\u003c EOF\nfile '/path/to/clip_001.mp4'\nfile '/path/to/clip_002.mp4'\nfile '/path/to/clip_003.mp4'\nEOF\n\n# 2. Concatenate (no re-encoding - fast!)\nffmpeg -f concat -safe 0 -i concat_list.txt -c copy output.mp4\n```\n\n**Pros:** Ultra-fast (no re-encoding), perfect quality preservation\n**Cons:** Requires identical encoding parameters\n\n### Method 2: Re-encode Concatenation\n\n**Use when:** Clips have different codecs/settings, or adding transitions\n\n```bash\nffmpeg -i clip_001.mp4 -i clip_002.mp4 -i clip_003.mp4 \\\n -filter_complex \"[0:v][1:v][2:v]concat=n=3:v=1:a=0[outv]\" \\\n -map \"[outv]\" \\\n -c:v libx264 -preset slow -crf 18 \\\n output.mp4\n```\n\n**Pros:** Handles any input, allows filtering\n**Cons:** Slower, potential quality loss\n\n---\n\n## Transition Effects\n\n### Crossfade Transition\n\n```bash\n# 2 clips with 1-second crossfade\nffmpeg -i clip1.mp4 -i clip2.mp4 \\\n -filter_complex \\\n \"[0:v][1:v]xfade=transition=fade:duration=1:offset=4[outv]\" \\\n -map \"[outv]\" \\\n -c:v libx264 -crf 18 \\\n output.mp4\n```\n\n**Transition types for xfade:**\n- `fade` - Simple crossfade (most common)\n- `wipeleft` - Wipe from right to left\n- `wiperight` - Wipe from left to right\n- `wipeup` - Wipe from bottom to top\n- `wipedown` - Wipe from top to bottom\n- `slideleft` - Slide transition to left\n- `slideright` - Slide transition to right\n- `circlecrop` - Circular reveal\n- `rectcrop` - Rectangular reveal\n- `distance` - Smooth morph\n- `fadeblack` - Fade to black then in\n\n### Multiple Clips with Crossfades\n\n```python\n#!/usr/bin/env python3\n\"\"\"Generate FFmpeg command for N clips with crossfades\"\"\"\n\ndef generate_crossfade_command(clips, fade_duration=0.5, output=\"final.mp4\"):\n \"\"\"\n Generate FFmpeg command for multiple clips with crossfades\n\n Args:\n clips: List of video file paths\n fade_duration: Transition duration in seconds\n output: Output filename\n \"\"\"\n n = len(clips)\n\n # Build input arguments\n inputs = \" \".join([f\"-i {clip}\" for clip in clips])\n\n # Build filter complex\n filter_parts = []\n\n # Calculate offsets (each clip minus fade duration)\n # Assume each clip is same duration\n clip_duration = 5 # seconds (adjust as needed)\n offset = clip_duration - fade_duration\n\n current_label = \"0:v\"\n for i in range(1, n):\n next_input = f\"{i}:v\"\n current_offset = offset * i\n temp_label = f\"v{i}\"\n\n fade_filter = (\n f\"[{current_label}][{next_input}]\"\n f\"xfade=transition=fade:\"\n f\"duration={fade_duration}:\"\n f\"offset={current_offset}[{temp_label}]\"\n )\n\n filter_parts.append(fade_filter)\n current_label = temp_label\n\n filter_complex = \";\".join(filter_parts)\n\n # Build final command\n cmd = (\n f\"ffmpeg {inputs} \"\n f'-filter_complex \"{filter_complex}\" '\n f\"-map '[{current_label}]' \"\n f\"-c:v libx264 -preset slow -crf 18 \"\n f\"{output}\"\n )\n\n return cmd\n\n# Example usage\nclips = [\n \"clip_001.mp4\",\n \"clip_002.mp4\",\n \"clip_003.mp4\",\n \"clip_004.mp4\",\n \"clip_005.mp4\"\n]\n\ncommand = generate_crossfade_command(clips, fade_duration=0.5)\nprint(command)\n```\n\n---\n\n## Advanced Transitions\n\n### Zoom Transition\n\n```bash\n# Zoom in from clip1 to clip2\nffmpeg -i clip1.mp4 -i clip2.mp4 \\\n -filter_complex \\\n \"[0:v]scale=iw*1.2:ih*1.2,crop=iw/1.2:ih/1.2:(iw-ow)/2:(ih-oh)/2[v0]; \\\n [v0][1:v]xfade=transition=fade:duration=1:offset=4[outv]\" \\\n -map \"[outv]\" \\\n -c:v libx264 -crf 18 \\\n output.mp4\n```\n\n### Motion Blur Transition\n\n```bash\n# Add motion blur during transition\nffmpeg -i clip1.mp4 -i clip2.mp4 \\\n -filter_complex \\\n \"[0:v]minterpolate=fps=60:mi_mode=mci[v0]; \\\n [v0][1:v]xfade=transition=fade:duration=0.5:offset=4[outv]\" \\\n -map \"[outv]\" \\\n -r 30 \\\n -c:v libx264 -crf 18 \\\n output.mp4\n```\n\n### Fade to Black Transition\n\n```bash\n# Fade clip1 to black, then fade in clip2\nffmpeg -i clip1.mp4 -i clip2.mp4 \\\n -filter_complex \\\n \"[0:v]fade=t=out:st=4:d=0.5[v0]; \\\n [1:v]fade=t=in:st=0:d=0.5[v1]; \\\n [v0][v1]concat=n=2:v=1:a=0[outv]\" \\\n -map \"[outv]\" \\\n -c:v libx264 -crf 18 \\\n output.mp4\n```\n\n---\n\n## Audio Handling\n\n### Concatenate with Audio\n\n```bash\n# Concat with both video and audio\nffmpeg -f concat -safe 0 -i concat_list.txt \\\n -c:v copy -c:a copy \\\n output.mp4\n```\n\n### Crossfade Audio During Video Transitions\n\n```bash\nffmpeg -i clip1.mp4 -i clip2.mp4 \\\n -filter_complex \\\n \"[0:v][1:v]xfade=transition=fade:duration=1:offset=4[outv]; \\\n [0:a][1:a]acrossfade=d=1[outa]\" \\\n -map \"[outv]\" -map \"[outa]\" \\\n -c:v libx264 -crf 18 -c:a aac \\\n output.mp4\n```\n\n### Add Background Music\n\n```bash\n# Add music to silent video\nffmpeg -i video.mp4 -i music.mp3 \\\n -c:v copy -c:a aac \\\n -shortest \\\n output.mp4\n\n# Mix existing audio with music\nffmpeg -i video.mp4 -i music.mp3 \\\n -filter_complex \\\n \"[0:a][1:a]amix=inputs=2:duration=first:dropout_transition=2[aout]\" \\\n -map 0:v -map \"[aout]\" \\\n -c:v copy -c:a aac \\\n output.mp4\n```\n\n---\n\n## Quality Preservation\n\n### High-Quality Encoding Settings\n\n```bash\n# h264 (most compatible)\nffmpeg -i input.mp4 \\\n -c:v libx264 \\\n -preset slow \\ # slow = better compression\n -crf 18 \\ # 18 = visually lossless\n -pix_fmt yuv420p \\ # ensure compatibility\n -movflags +faststart \\ # web streaming optimization\n output.mp4\n\n# h265 (better compression, less compatible)\nffmpeg -i input.mp4 \\\n -c:v libx265 \\\n -preset slow \\\n -crf 20 \\ # 20 for h265 ≈ 18 for h264\n -pix_fmt yuv420p \\\n output.mp4\n```\n\n### Resolution & FPS Enforcement\n\n```bash\n# Force resolution and FPS\nffmpeg -i input.mp4 \\\n -vf \"scale=768:1024:force_original_aspect_ratio=decrease,pad=768:1024:(ow-iw)/2:(oh-ih)/2\" \\\n -r 25 \\\n -c:v libx264 -crf 18 \\\n output.mp4\n```\n\n---\n\n## Validation Before Concatenation\n\n### Pre-Flight Check Script\n\n```python\n#!/usr/bin/env python3\n\"\"\"Validate clips before concatenation\"\"\"\n\nimport subprocess\nimport json\n\ndef get_video_info(video_path):\n \"\"\"Extract video metadata using ffprobe\"\"\"\n cmd = [\n 'ffprobe', '-v', 'error',\n '-select_streams', 'v:0',\n '-show_entries', 'stream=width,height,r_frame_rate,codec_name,duration',\n '-of', 'json',\n video_path\n ]\n\n result = subprocess.run(cmd, capture_output=True, text=True)\n data = json.loads(result.stdout)\n\n stream = data['streams'][0]\n\n # Parse frame rate\n fps_str = stream['r_frame_rate']\n num, den = map(int, fps_str.split('/'))\n fps = num / den\n\n return {\n 'width': stream['width'],\n 'height': stream['height'],\n 'fps': round(fps, 2),\n 'codec': stream['codec_name'],\n 'duration': float(stream.get('duration', 0))\n }\n\ndef validate_clips_for_concat(clips):\n \"\"\"Check if clips can be safely concatenated\"\"\"\n issues = []\n info_list = []\n\n for clip in clips:\n try:\n info = get_video_info(clip)\n info_list.append(info)\n except Exception as e:\n issues.append(f\"{clip}: Failed to read ({e})\")\n return False, issues\n\n # Check consistency\n reference = info_list[0]\n\n for i, info in enumerate(info_list[1:], 1):\n if info['width'] != reference['width'] or info['height'] != reference['height']:\n issues.append(\n f\"Clip {i}: Resolution mismatch \"\n f\"({info['width']}x{info['height']} vs {reference['width']}x{reference['height']})\"\n )\n\n if abs(info['fps'] - reference['fps']) > 0.1:\n issues.append(\n f\"Clip {i}: FPS mismatch \"\n f\"({info['fps']} vs {reference['fps']})\"\n )\n\n if info['codec'] != reference['codec']:\n issues.append(\n f\"Clip {i}: Codec mismatch \"\n f\"({info['codec']} vs {reference['codec']})\"\n )\n\n if issues:\n return False, issues\n else:\n return True, info_list\n\n# Example usage\nclips = ['clip_001.mp4', 'clip_002.mp4', 'clip_003.mp4']\nvalid, result = validate_clips_for_concat(clips)\n\nif valid:\n print(\"✓ All clips compatible for concatenation\")\n print(f\"Resolution: {result[0]['width']}x{result[0]['height']}\")\n print(f\"FPS: {result[0]['fps']}\")\n print(f\"Codec: {result[0]['codec']}\")\nelse:\n print(\"✗ Clips incompatible:\")\n for issue in result:\n print(f\" - {issue}\")\n```\n\n---\n\n## Production Pipeline\n\n### Complete Concatenation Script\n\n```python\n#!/usr/bin/env python3\n\"\"\"Production-ready video concatenation with transitions\"\"\"\n\nimport subprocess\nimport os\nimport json\nfrom pathlib import Path\n\nclass VideoConcatenator:\n def __init__(self, output_dir=\"output\"):\n self.output_dir = Path(output_dir)\n self.output_dir.mkdir(exist_ok=True)\n\n def validate_clips(self, clips):\n \"\"\"Validate all clips before processing\"\"\"\n print(\"[Validation] Checking clips...\")\n\n valid, result = validate_clips_for_concat(clips)\n\n if not valid:\n print(\"[Validation] ✗ FAILED\")\n for issue in result:\n print(f\" {issue}\")\n return False\n\n print(\"[Validation] ✓ All clips compatible\")\n return True\n\n def concatenate_simple(self, clips, output_name=\"combined.mp4\"):\n \"\"\"Simple concatenation without transitions (fast)\"\"\"\n concat_file = self.output_dir / \"concat_list.txt\"\n\n with open(concat_file, 'w') as f:\n for clip in clips:\n abs_path = Path(clip).resolve()\n f.write(f\"file '{abs_path}'\\n\")\n\n output_path = self.output_dir / output_name\n\n cmd = [\n 'ffmpeg', '-y',\n '-f', 'concat',\n '-safe', '0',\n '-i', str(concat_file),\n '-c', 'copy',\n str(output_path)\n ]\n\n print(f\"[Concat] Combining {len(clips)} clips...\")\n subprocess.run(cmd, check=True, capture_output=True)\n\n concat_file.unlink() # Cleanup\n\n print(f\"[Concat] ✓ Output: {output_path}\")\n return output_path\n\n def concatenate_with_transitions(\n self,\n clips,\n fade_duration=0.5,\n output_name=\"combined_transitions.mp4\"\n ):\n \"\"\"Concatenation with crossfade transitions (slower)\"\"\"\n print(f\"[Concat] Applying {fade_duration}s crossfades...\")\n\n output_path = self.output_dir / output_name\n\n # Build FFmpeg command\n inputs = []\n for clip in clips:\n inputs.extend(['-i', clip])\n\n # Generate filter complex\n filter_parts = []\n current_label = \"0:v\"\n\n # Calculate clip duration (assume all clips same duration)\n duration_cmd = [\n 'ffprobe', '-v', 'error',\n '-show_entries', 'format=duration',\n '-of', 'default=noprint_wrappers=1:nokey=1',\n clips[0]\n ]\n duration = float(subprocess.run(duration_cmd, capture_output=True, text=True).stdout.strip())\n offset = duration - fade_duration\n\n for i in range(1, len(clips)):\n next_input = f\"{i}:v\"\n current_offset = offset * i\n temp_label = f\"v{i}\"\n\n fade_filter = (\n f\"[{current_label}][{next_input}]\"\n f\"xfade=transition=fade:duration={fade_duration}:offset={current_offset}[{temp_label}]\"\n )\n\n filter_parts.append(fade_filter)\n current_label = temp_label\n\n filter_complex = \";\".join(filter_parts)\n\n cmd = [\n 'ffmpeg', '-y',\n *inputs,\n '-filter_complex', filter_complex,\n '-map', f'[{current_label}]',\n '-c:v', 'libx264',\n '-preset', 'slow',\n '-crf', '18',\n '-pix_fmt', 'yuv420p',\n '-movflags', '+faststart',\n str(output_path)\n ]\n\n subprocess.run(cmd, check=True, capture_output=True)\n\n print(f\"[Concat] ✓ Output: {output_path}\")\n return output_path\n\n# Example usage\nif __name__ == \"__main__\":\n clips = [\n \"E:/ComfyUI/output/clip_001.mp4\",\n \"E:/ComfyUI/output/clip_002.mp4\",\n \"E:/ComfyUI/output/clip_003.mp4\"\n ]\n\n concatenator = VideoConcatenator(output_dir=\"E:/ComfyUI/output/final\")\n\n if concatenator.validate_clips(clips):\n # Method 1: Fast, no transitions\n # concatenator.concatenate_simple(clips, \"sage_video_final.mp4\")\n\n # Method 2: With transitions\n concatenator.concatenate_with_transitions(\n clips,\n fade_duration=0.5,\n output_name=\"sage_video_final.mp4\"\n )\n```\n\n---\n\n## Troubleshooting\n\n### Issue: \"Non-monotonous DTS in output stream\"\n**Fix:** Re-encode instead of using `-c copy`\n\n### Issue: Audio/video out of sync\n**Fix:** Use `-async 1` or `-vsync 2`\n\n### Issue: Transitions look jerky\n**Fix:** Increase transition duration or use motion blur\n\n### Issue: File size too large\n**Fix:** Lower CRF value (higher compression) or reduce resolution\n\n### Issue: Clips have different resolutions\n**Fix:** Scale all to same resolution before concatenation:\n```bash\nffmpeg -i input.mp4 -vf scale=768:1024 -c:v libx264 -crf 18 output.mp4\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":13515,"content_sha256":"8232cb0ce1b908e5b85069f7f24b8c9da6c98b4b5019ed6de097a46466a45126"},{"filename":"references/evolution.md","content":"# Skill Evolution & Changelog\n\nTrack updates, new techniques, and user-specific learnings for the ComfyUI Video Production skill.\n\n---\n\n## Changelog\n\n### v1.0.0 (February 2026 - Initial Release)\n\n**Core Features:**\n- Complete keyframe-to-video pipeline\n- Batch I2V processing system\n- Professional video concatenation with transitions\n- ComfyUI instance management & health monitoring\n- Multi-instance load balancing\n- Auto-restart & recovery procedures\n- Validation suite for pre/post generation\n- FFmpeg integration for transitions\n\n**Supported Models:**\n- LTX-2 (4K production video)\n- Wan 2.2 MoE (film-quality)\n- Wan 2.1 14B & 1.3B\n- AnimateDiff V3\n- SVD (Stable Video Diffusion)\n\n**Documentation:**\n- Main SKILL.md with 3 core pipelines\n- instance-management.md - ComfyUI health & restart\n- concatenation.md - FFmpeg transitions & audio\n- api-reference.md - ComfyUI REST API guide\n- evolution.md - This file\n\n**Key Capabilities:**\n- Automatic error recovery with retry strategies\n- Progress tracking with real-time ETA\n- Quality validation (resolution, FPS, codec)\n- Rollback & versioning support\n- RTX 50 Series optimizations (NVFP4/NVFP8)\n- AMD ROCm support (native in ComfyUI v0.8.1+)\n\n---\n\n## Monitoring Sources\n\n### I2V Model Releases (Check Weekly)\n\n**HuggingFace Trending**\n- https://huggingface.co/models?sort=trending&pipeline_tag=video-generation\n- Watch for: New video diffusion models, improved versions of Wan/LTX\n\n**GitHub Repositories**\n- https://github.com/Lightricks/LTX-Video - LTX updates\n- https://github.com/alibaba/VideoX - Wan updates\n- https://github.com/Kosinkadink/ComfyUI-AnimateDiff-Evolved - AnimateDiff\n- https://github.com/comfyanonymous/ComfyUI - Core ComfyUI updates\n\n**Research Papers**\n- https://arxiv.org/list/cs.CV/recent - Computer vision (video gen)\n- https://huggingface.co/papers - Daily ML papers\n- Search: \"image to video\", \"video diffusion\", \"temporal consistency\"\n\n### ComfyUI Updates (Check Weekly)\n\n**Official Releases**\n- https://github.com/comfyanonymous/ComfyUI/releases\n- Watch for: API changes, performance improvements, new features\n\n**Custom Nodes**\n- https://github.com/ltdrdata/ComfyUI-Manager - Manager updates\n- https://github.com/Fannovel16/ComfyUI-Frame-Interpolation - RIFE/FILM\n- https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite - Video tools\n\n### Community Knowledge (Check Monthly)\n\n- r/comfyui - Reddit community\n- r/StableDiffusion - General AI video discussions\n- ComfyUI Discord - Real-time community help\n- Civitai forums - Model/workflow discussions\n\n---\n\n## Update Protocol\n\n### When New I2V Model Releases\n\n1. **Evaluate Relevance**\n - Does it improve on current recommendations?\n - What's the quality vs performance tradeoff?\n - VRAM requirements feasible for target users?\n\n2. **Test Compatibility**\n - Can it be loaded in ComfyUI?\n - Required custom nodes available?\n - Works with existing workflow patterns?\n\n3. **Benchmark Performance**\n - Test on same keyframes as existing models\n - Measure: quality, speed, VRAM usage, consistency\n - Compare to Wan 2.2, LTX-2, AnimateDiff baselines\n\n4. **Update Documentation**\n - Add to model comparison table in SKILL.md\n - Create workflow template if significantly different\n - Document special settings or gotchas\n - Update references/i2v-workflows.md (when created)\n\n5. **Log Change**\n - Add entry to changelog below\n\n### When ComfyUI API Changes\n\n1. **Review Breaking Changes**\n - Check API reference doc for affected endpoints\n - Test existing code against new version\n\n2. **Update Code Examples**\n - Modify api-reference.md examples\n - Update Python client code\n - Test all example scripts\n\n3. **Document Migration Path**\n - If breaking: provide migration guide\n - Note version requirements\n\n### When User Reports Issue\n\n1. **Reproduce & Document**\n - What workflow/settings triggered it?\n - Can it be consistently reproduced?\n - Error messages or failure mode?\n\n2. **Research Solution**\n - Check ComfyUI issues on GitHub\n - Search community forums/Discord\n - Test potential fixes\n\n3. **Update Documentation**\n - Add to troubleshooting section if common issue\n - Update relevant reference guide\n - Add validation check to prevent if possible\n\n4. **Log Change**\n - Note issue and fix in changelog\n\n---\n\n## User-Specific Learnings\n\nTrack what works for specific user setups and projects.\n\n### Hardware Profile\n\n**User:** MCKRUZ\n**GPU:** NVIDIA RTX 5090 (32GB VRAM)\n**OS:** Windows 11 Pro\n**ComfyUI:** v0.8.1+\n\n**Capabilities:**\n- Can run Wan 2.2 14B natively\n- LTX-2 4K generation without optimization\n- Batch multiple workflows simultaneously\n- Use NVFP4/NVFP8 precision for 3x speedup\n\n**Optimal Settings:**\n```bash\n# ComfyUI launch flags\n--highvram \\\n--fp8_e4m3fn-unet \\\n--reserve-vram 7\n```\n\n### Project: Sage Character Video Series\n\n**Goal:** Multi-shot narrative videos (30+ seconds)\n**Character:** Sage (reddish-brown hair, green eyes, fair skin)\n**Style:** Photorealistic, natural lighting, intimate/sensual\n\n**Workflow Preferences:**\n- Keyframe generation: FLUX.1-dev + IP-Adapter (0.80 weight)\n- I2V model: Wan 2.2 MoE 14B (film-quality aesthetics)\n- Resolution: 768x1024 (portrait) or 832x1216 (larger)\n- FPS: 16 (matches Wan 2.2 output)\n- Transitions: 0.5s crossfade (smooth but not slow)\n\n**What Worked:**\n- ✓ Generating 5 keyframes first, validating consistency before I2V\n- ✓ Using consistent motion prompts with \"consistent identity, same person\" prefix\n- ✓ Staggering I2V submissions (3-5 minute wait between clips)\n- ✓ Validating each clip immediately after generation\n\n**What Didn't Work:**\n- ✗ Submitting all 5 I2V jobs at once (overwhelmed queue)\n- ✗ Using cv2.VideoWriter for concatenation (quality loss, wrong codec)\n- ✗ Not validating FPS before concat (got 25fps instead of 16fps)\n- ✗ Hard-coded wait times (some clips took longer, some faster)\n- ✗ Manual file selection for concatenation (forgot clips 1 & 4)\n\n**Lessons Learned:**\n1. **Always validate before proceeding** - Check keyframes, then check videos\n2. **Use FFmpeg, not cv2** - Better quality, proper codec support\n3. **Automate everything** - Manual steps = mistakes\n4. **Implement retry logic** - Some generations fail randomly\n5. **Monitor ComfyUI health** - Can stall without errors\n\n---\n\n## Feature Roadmap\n\n### v1.1.0 (Planned)\n\n**New Features:**\n- Keyframe generation reference guide\n- I2V workflow templates for all supported models\n- Validation reference with face consistency checking\n- Troubleshooting guide with common issues\n\n**Improvements:**\n- Add frame interpolation between I2V clips\n- Support for audio addition/mixing\n- Color grading pipeline\n- Upscaling integration\n\n### v1.2.0 (Future)\n\n**Advanced Features:**\n- Multi-GPU support for parallel generation\n- Cloud instance integration (RunPod, Vast.ai)\n- Voice synthesis integration (TTS Audio Suite)\n- Lip-sync pipeline (Wav2Lip, SadTalker)\n\n---\n\n## Research Tasks\n\n### Weekly\n- [ ] Check HuggingFace for new video generation models\n- [ ] Review ComfyUI releases for breaking changes\n- [ ] Monitor community forums for common issues\n\n### Monthly\n- [ ] Deep dive on any major new I2V model releases\n- [ ] Review video generation research papers\n- [ ] Test new custom nodes for video workflows\n- [ ] Update benchmark comparisons\n\n### Quarterly\n- [ ] Full skill audit - are recommendations still current?\n- [ ] Remove deprecated models/techniques\n- [ ] Major version bump if significant changes\n\n---\n\n## Integration Opportunities\n\n### With Other Skills\n\n**comfyui-character-gen**\n- Use for generating consistent keyframes with LoRA/IP-Adapter\n- Character consistency validation across frames\n- Identity preservation techniques\n\n**youtube-uploader**\n- Direct upload to YouTube after production\n- Metadata extraction for title/description\n- Thumbnail generation from keyframes\n\n**video-assembly** (if exists)\n- Advanced editing and color grading\n- Multi-track audio mixing\n- Effects and overlays\n\n---\n\n## Community Contributions\n\nIf this skill helps you, consider contributing:\n\n1. **Report Issues**\n - Document problems you encounter\n - Include workflow, settings, error messages\n - Suggest improvements\n\n2. **Share Discoveries**\n - New model settings that work well\n - Workflow optimizations\n - Troubleshooting solutions\n\n3. **Extend Documentation**\n - Add examples for your use case\n - Create guides for specific techniques\n - Document edge cases\n\n4. **Contribute Code**\n - Improve Python client\n - Add new validation checks\n - Optimize batch processing\n\n---\n\n## Version History\n\n| Version | Date | Key Changes |\n|---------|------|-------------|\n| v1.0.0 | 2026-02-16 | Initial release with core pipelines |\n| v1.0.1 | TBD | Bug fixes and documentation improvements |\n| v1.1.0 | TBD | New reference guides and validation suite |\n| v1.2.0 | TBD | Advanced features and integrations |\n\n---\n\n## Contact & Support\n\n**GitHub Repo:** https://github.com/MCKRUZ/ComfyUI-Expert\n\n**Issues:** Report problems or request features via GitHub Issues\n\n**Community:** Join ComfyUI Discord for real-time help\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9083,"content_sha256":"2372bef4a749fd86b7cbc134fce43b5d5bc726ce640b9b48c969171e50b5fd75"},{"filename":"references/instance-management.md","content":"# ComfyUI Instance Management\n\nRobust management of ComfyUI instances with health monitoring, auto-restart, and multi-instance orchestration.\n\n---\n\n## Health Monitoring\n\n### Endpoint Checks\n\n```python\nimport requests\nimport time\n\ndef check_comfyui_health(url=\"http://127.0.0.1:8188\"):\n \"\"\"Check if ComfyUI is responsive\"\"\"\n endpoints = {\n \"system_stats\": f\"{url}/system_stats\",\n \"queue\": f\"{url}/queue\",\n \"history\": f\"{url}/history\",\n \"prompt\": f\"{url}/prompt\"\n }\n\n health = {}\n for name, endpoint in endpoints.items():\n try:\n response = requests.get(endpoint, timeout=5)\n health[name] = response.status_code == 200\n except:\n health[name] = False\n\n return all(health.values()), health\n```\n\n### Queue Monitoring\n\n```python\ndef monitor_queue(url=\"http://127.0.0.1:8188\", interval=30):\n \"\"\"Monitor queue for stalls\"\"\"\n previous_queue_size = None\n stall_count = 0\n\n while True:\n try:\n response = requests.get(f\"{url}/queue\")\n data = response.json()\n\n current_queue = data.get(\"queue_running\", [])\n queue_size = len(current_queue)\n\n # Check if queue is stalled\n if queue_size > 0 and queue_size == previous_queue_size:\n stall_count += 1\n if stall_count >= 10: # 5 minutes at 30s intervals\n return \"STALLED\"\n else:\n stall_count = 0\n\n previous_queue_size = queue_size\n time.sleep(interval)\n\n except Exception as e:\n return f\"ERROR: {e}\"\n```\n\n### VRAM Monitoring\n\n```python\ndef check_vram_usage(threshold_gb=28):\n \"\"\"Monitor VRAM usage (requires nvidia-smi)\"\"\"\n import subprocess\n\n try:\n result = subprocess.run(\n ['nvidia-smi', '--query-gpu=memory.used', '--format=csv,noheader,nounits'],\n capture_output=True,\n text=True\n )\n\n vram_used_mb = int(result.stdout.strip())\n vram_used_gb = vram_used_mb / 1024\n\n if vram_used_gb > threshold_gb:\n return \"HIGH_VRAM\", vram_used_gb\n\n return \"OK\", vram_used_gb\n\n except Exception as e:\n return \"UNKNOWN\", 0\n```\n\n---\n\n## Auto-Restart Procedures\n\n### Graceful Restart\n\n```python\nimport subprocess\nimport psutil\nimport time\n\ndef restart_comfyui(\n comfyui_path=\"E:/ComfyUI-Easy-Install/ComfyUI\",\n port=8188,\n python_path=\"python\"\n):\n \"\"\"Gracefully restart ComfyUI instance\"\"\"\n\n print(\"[Restart] Saving queue state...\")\n save_queue_state(port)\n\n print(\"[Restart] Finding ComfyUI process...\")\n killed = kill_comfyui_process(port)\n\n if killed:\n print(\"[Restart] Process terminated\")\n else:\n print(\"[Restart] No process found (may have crashed)\")\n\n print(\"[Restart] Waiting for port release...\")\n wait_for_port_release(port, timeout=30)\n\n print(\"[Restart] Starting ComfyUI...\")\n start_comfyui(comfyui_path, port, python_path)\n\n print(\"[Restart] Waiting for API to respond...\")\n wait_for_api_ready(port, timeout=120)\n\n print(\"[Restart] Restoring queue state...\")\n restore_queue_state(port)\n\n print(\"[Restart] ✓ ComfyUI restarted successfully\")\n```\n\n### Save/Restore Queue\n\n```python\nimport json\n\ndef save_queue_state(port=8188):\n \"\"\"Save pending queue items before restart\"\"\"\n url = f\"http://127.0.0.1:{port}/queue\"\n\n try:\n response = requests.get(url)\n data = response.json()\n\n with open(f\"queue_backup_{port}.json\", \"w\") as f:\n json.dump(data, f, indent=2)\n\n return True\n except:\n return False\n\ndef restore_queue_state(port=8188):\n \"\"\"Restore queue after restart\"\"\"\n backup_file = f\"queue_backup_{port}.json\"\n\n if not os.path.exists(backup_file):\n return False\n\n with open(backup_file, \"r\") as f:\n data = json.load(f)\n\n # Re-submit pending items\n for item in data.get(\"queue_pending\", []):\n # Extract workflow from queue item\n workflow = item[2] # Workflow is 3rd element in queue tuple\n submit_workflow(workflow, port)\n\n os.remove(backup_file)\n return True\n```\n\n### Process Management\n\n```python\ndef kill_comfyui_process(port=8188):\n \"\"\"Find and kill ComfyUI process by port\"\"\"\n for proc in psutil.process_iter(['pid', 'name', 'connections']):\n try:\n for conn in proc.connections():\n if conn.laddr.port == port:\n proc.terminate()\n proc.wait(timeout=10)\n return True\n except:\n continue\n\n return False\n\ndef wait_for_port_release(port, timeout=30):\n \"\"\"Wait until port is no longer in use\"\"\"\n start = time.time()\n\n while time.time() - start \u003c timeout:\n in_use = False\n for proc in psutil.process_iter(['connections']):\n try:\n for conn in proc.connections():\n if conn.laddr.port == port:\n in_use = True\n break\n except:\n continue\n if in_use:\n break\n\n if not in_use:\n return True\n\n time.sleep(1)\n\n return False\n\ndef start_comfyui(comfyui_path, port=8188, python_path=\"python\"):\n \"\"\"Start ComfyUI process\"\"\"\n cmd = [\n python_path,\n \"main.py\",\n \"--port\", str(port),\n \"--highvram\",\n \"--fp8_e4m3fn-unet\"\n ]\n\n subprocess.Popen(\n cmd,\n cwd=comfyui_path,\n stdout=subprocess.DEVNULL,\n stderr=subprocess.DEVNULL\n )\n\ndef wait_for_api_ready(port, timeout=120):\n \"\"\"Wait for ComfyUI API to become responsive\"\"\"\n start = time.time()\n url = f\"http://127.0.0.1:{port}/queue\"\n\n while time.time() - start \u003c timeout:\n try:\n response = requests.get(url, timeout=5)\n if response.status_code == 200:\n return True\n except:\n pass\n\n time.sleep(2)\n\n return False\n```\n\n---\n\n## Multi-Instance Management\n\n### Instance Configuration\n\n```python\nINSTANCES = {\n \"primary\": {\n \"port\": 8188,\n \"path\": \"E:/ComfyUI-Easy-Install/ComfyUI\",\n \"purpose\": \"I2V generation\",\n \"priority\": 1\n },\n \"secondary\": {\n \"port\": 8189,\n \"path\": \"E:/ComfyUI-Easy-Install/ComfyUI\",\n \"purpose\": \"upscaling/post-processing\",\n \"priority\": 2\n },\n \"backup\": {\n \"port\": 8190,\n \"path\": \"E:/ComfyUI-Easy-Install/ComfyUI\",\n \"purpose\": \"failover standby\",\n \"priority\": 3\n }\n}\n```\n\n### Load Balancer\n\n```python\nclass ComfyUILoadBalancer:\n def __init__(self, instances):\n self.instances = instances\n self.round_robin_index = 0\n\n def get_healthiest_instance(self):\n \"\"\"Return instance with lowest queue size\"\"\"\n queue_sizes = {}\n\n for name, config in self.instances.items():\n try:\n url = f\"http://127.0.0.1:{config['port']}/queue\"\n response = requests.get(url, timeout=5)\n data = response.json()\n queue_sizes[name] = len(data.get(\"queue_running\", []))\n except:\n queue_sizes[name] = float('inf') # Mark as unavailable\n\n return min(queue_sizes, key=queue_sizes.get)\n\n def get_next_round_robin(self):\n \"\"\"Return next instance in round-robin\"\"\"\n instances_list = list(self.instances.keys())\n instance = instances_list[self.round_robin_index]\n self.round_robin_index = (self.round_robin_index + 1) % len(instances_list)\n return instance\n\n def submit_to_best_instance(self, workflow):\n \"\"\"Submit workflow to best available instance\"\"\"\n instance_name = self.get_healthiest_instance()\n config = self.instances[instance_name]\n\n return submit_workflow(workflow, config['port'])\n```\n\n### Failover Handler\n\n```python\ndef submit_with_failover(workflow, primary_port=8188, backup_ports=[8189, 8190]):\n \"\"\"Try primary, fall back to backups if needed\"\"\"\n ports = [primary_port] + backup_ports\n\n for port in ports:\n try:\n result = submit_workflow(workflow, port)\n print(f\"[Failover] Submitted to port {port}\")\n return result\n except Exception as e:\n print(f\"[Failover] Port {port} failed: {e}\")\n continue\n\n raise Exception(\"All instances failed\")\n```\n\n---\n\n## Startup Scripts\n\n### Windows (PowerShell)\n\n```powershell\n# start-comfyui-multi.ps1\n# Start multiple ComfyUI instances\n\n$instances = @(\n @{ Port = 8188; Purpose = \"Primary I2V\" },\n @{ Port = 8189; Purpose = \"Upscaling\" },\n @{ Port = 8190; Purpose = \"Backup\" }\n)\n\n$comfyuiPath = \"E:\\ComfyUI-Easy-Install\\ComfyUI\"\n\nforeach ($instance in $instances) {\n $port = $instance.Port\n $purpose = $instance.Purpose\n\n Write-Host \"Starting ComfyUI on port $port ($purpose)...\"\n\n Start-Process python -ArgumentList @(\n \"main.py\",\n \"--port\", $port,\n \"--highvram\",\n \"--fp8_e4m3fn-unet\"\n ) -WorkingDirectory $comfyuiPath -WindowStyle Hidden\n\n Start-Sleep -Seconds 5\n}\n\nWrite-Host \"All instances started!\"\nWrite-Host \"Primary: http://localhost:8188\"\nWrite-Host \"Secondary: http://localhost:8189\"\nWrite-Host \"Backup: http://localhost:8190\"\n```\n\n### Linux/Mac (Bash)\n\n```bash\n#!/bin/bash\n# start-comfyui-multi.sh\n\nCOMFYUI_PATH=\"$HOME/ComfyUI\"\n\nstart_instance() {\n local port=$1\n local purpose=$2\n\n echo \"Starting ComfyUI on port $port ($purpose)...\"\n\n cd \"$COMFYUI_PATH\"\n python main.py \\\n --port $port \\\n --highvram \\\n --fp8_e4m3fn-unet \\\n > \"logs/comfyui_$port.log\" 2>&1 &\n\n sleep 5\n}\n\nstart_instance 8188 \"Primary I2V\"\nstart_instance 8189 \"Upscaling\"\nstart_instance 8190 \"Backup\"\n\necho \"All instances started!\"\necho \"Primary: http://localhost:8188\"\necho \"Secondary: http://localhost:8189\"\necho \"Backup: http://localhost:8190\"\n```\n\n---\n\n## Monitoring Dashboard (CLI)\n\n```python\n#!/usr/bin/env python3\n\"\"\"Real-time monitoring of ComfyUI instances\"\"\"\n\nimport requests\nimport time\nimport os\nfrom datetime import datetime\n\ndef clear_screen():\n os.system('cls' if os.name == 'nt' else 'clear')\n\ndef get_instance_status(port):\n \"\"\"Get status of ComfyUI instance\"\"\"\n url = f\"http://127.0.0.1:{port}\"\n\n try:\n # Check queue\n queue_response = requests.get(f\"{url}/queue\", timeout=2)\n queue_data = queue_response.json()\n\n running = len(queue_data.get(\"queue_running\", []))\n pending = len(queue_data.get(\"queue_pending\", []))\n\n # Check system stats\n stats_response = requests.get(f\"{url}/system_stats\", timeout=2)\n stats_data = stats_response.json()\n\n vram = stats_data.get(\"devices\", [{}])[0].get(\"vram_used\", 0) / 1024 # GB\n\n return {\n \"status\": \"ONLINE\",\n \"running\": running,\n \"pending\": pending,\n \"vram_gb\": round(vram, 2)\n }\n except:\n return {\n \"status\": \"OFFLINE\",\n \"running\": 0,\n \"pending\": 0,\n \"vram_gb\": 0\n }\n\ndef monitor_instances(instances):\n \"\"\"Display real-time status of all instances\"\"\"\n while True:\n clear_screen()\n\n print(\"=\" * 80)\n print(f\"ComfyUI Instance Monitor - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\")\n print(\"=\" * 80)\n\n for name, config in instances.items():\n port = config[\"port\"]\n purpose = config[\"purpose\"]\n status = get_instance_status(port)\n\n status_color = \"🟢\" if status[\"status\"] == \"ONLINE\" else \"🔴\"\n\n print(f\"\\n{status_color} {name.upper()} (Port {port}) - {purpose}\")\n print(f\" Status: {status['status']}\")\n print(f\" Queue: {status['running']} running, {status['pending']} pending\")\n print(f\" VRAM: {status['vram_gb']} GB\")\n\n print(\"\\n\" + \"=\" * 80)\n print(\"Press Ctrl+C to exit\")\n\n time.sleep(5)\n\nif __name__ == \"__main__\":\n INSTANCES = {\n \"primary\": {\"port\": 8188, \"purpose\": \"I2V generation\"},\n \"secondary\": {\"port\": 8189, \"purpose\": \"Upscaling\"},\n \"backup\": {\"port\": 8190, \"purpose\": \"Standby\"}\n }\n\n try:\n monitor_instances(INSTANCES)\n except KeyboardInterrupt:\n print(\"\\n\\nMonitoring stopped\")\n```\n\n---\n\n## Recovery Procedures\n\n### Procedure 1: Soft Recovery (No Restart)\n\n```python\ndef soft_recovery(port=8188):\n \"\"\"Attempt recovery without restarting\"\"\"\n url = f\"http://127.0.0.1:{port}\"\n\n # 1. Clear queue\n print(\"[Recovery] Clearing queue...\")\n try:\n requests.post(f\"{url}/queue\", json={\"clear\": True})\n except:\n pass\n\n # 2. Free memory\n print(\"[Recovery] Requesting garbage collection...\")\n try:\n requests.post(f\"{url}/free\", json={\"unload_models\": True})\n except:\n pass\n\n # 3. Wait and check\n time.sleep(10)\n is_healthy, _ = check_comfyui_health(url)\n\n return is_healthy\n```\n\n### Procedure 2: Hard Recovery (Restart)\n\n```python\ndef hard_recovery(port=8188, comfyui_path=\"E:/ComfyUI-Easy-Install/ComfyUI\"):\n \"\"\"Full restart recovery\"\"\"\n print(\"[Recovery] Hard recovery initiated...\")\n\n try:\n restart_comfyui(comfyui_path, port)\n return True\n except Exception as e:\n print(f\"[Recovery] Hard recovery failed: {e}\")\n return False\n```\n\n### Procedure 3: Emergency Failover\n\n```python\ndef emergency_failover(failed_port, backup_ports=[8189, 8190]):\n \"\"\"Switch to backup instance\"\"\"\n print(f\"[Failover] Port {failed_port} has failed\")\n\n for backup_port in backup_ports:\n is_healthy, _ = check_comfyui_health(f\"http://127.0.0.1:{backup_port}\")\n\n if is_healthy:\n print(f\"[Failover] Switching to port {backup_port}\")\n return backup_port\n\n print(\"[Failover] No backup instances available!\")\n return None\n```\n\n---\n\n## Best Practices\n\n1. **Always monitor health** - Check every 30-60 seconds\n2. **Save queue state before restart** - Prevent work loss\n3. **Keep backup instance ready** - Hot standby on different port\n4. **Log all restart events** - For debugging patterns\n5. **Use graceful termination** - Give ComfyUI time to save state\n6. **Test failover regularly** - Don't wait for emergencies\n7. **Monitor VRAM usage** - Memory leaks are common\n8. **Set restart thresholds** - Auto-restart after N failures\n\n---\n\n## Troubleshooting\n\n### ComfyUI won't start\n- Check if port is already in use: `netstat -ano | findstr :8188`\n- Verify Python environment is correct\n- Check CUDA/ROCm drivers are installed\n- Review startup logs for errors\n\n### Instance keeps crashing\n- Check VRAM usage - may be OOM\n- Review workflows for memory leaks\n- Update to latest ComfyUI version\n- Check for corrupted models\n\n### Queue stalls but process is running\n- Workflow may have infinite loop\n- Model download may be stuck\n- Custom node may be hanging\n- Try soft recovery first, then hard recovery\n\n### Failover not working\n- Verify backup instance is actually running\n- Check network/firewall settings\n- Ensure backup has same models loaded\n- Test failover mechanism regularly\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":15192,"content_sha256":"0764f66f48b57e889b4bdd7c4d0f2c34c4cd66bb03d3a78c700a61f996439490"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"ComfyUI Video Production Pipeline","type":"text"}]},{"type":"paragraph","content":[{"text":"End-to-end video production orchestration for ComfyUI with automatic error recovery, quality validation, and instance management.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Start: Which Pipeline?","type":"text"}]},{"type":"paragraph","content":[{"text":"Creating a multi-shot narrative video?","type":"text","marks":[{"type":"strong"}]},{"text":" → ","type":"text"},{"text":"Keyframe Pipeline","type":"text","marks":[{"type":"strong"}]},{"text":" - Generate keyframes → Animate → Stitch with transitions","type":"text"}]},{"type":"paragraph","content":[{"text":"Animating existing images?","type":"text","marks":[{"type":"strong"}]},{"text":" → ","type":"text"},{"text":"I2V Batch Pipeline","type":"text","marks":[{"type":"strong"}]},{"text":" - Load images → Queue I2V jobs → Auto-validate → Combine","type":"text"}]},{"type":"paragraph","content":[{"text":"Need smooth transitions between scenes?","type":"text","marks":[{"type":"strong"}]},{"text":" → ","type":"text"},{"text":"Transition Pipeline","type":"text","marks":[{"type":"strong"}]},{"text":" - Crossfades, motion blur, zoom effects via FFmpeg","type":"text"}]},{"type":"paragraph","content":[{"text":"ComfyUI stuck or crashed?","type":"text","marks":[{"type":"strong"}]},{"text":" → ","type":"text"},{"text":"Instance Manager","type":"text","marks":[{"type":"strong"}]},{"text":" - Auto-restart, health checks, queue monitoring","type":"text"}]},{"type":"paragraph","content":[{"text":"Debugging video issues?","type":"text","marks":[{"type":"strong"}]},{"text":" → ","type":"text"},{"text":"Validation Suite","type":"text","marks":[{"type":"strong"}]},{"text":" - Check resolution, FPS, codec, face consistency, color grading","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core Pipelines","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pipeline 1: Keyframe-to-Video (Complete Narrative)","type":"text"}]},{"type":"paragraph","content":[{"text":"Use when:","type":"text","marks":[{"type":"strong"}]},{"text":" Creating story-driven videos with multiple distinct shots","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"1. Keyframe Generation Phase\n - Generate consistent keyframes with IP-Adapter/LoRA\n - Validate face consistency, lighting, pose progression\n - Save to organized directory structure\n - Auto-retry failed generations\n\n2. I2V Animation Phase\n - Queue each keyframe to I2V model (Wan 2.2, LTX-2, AnimateDiff)\n - Monitor progress via ComfyUI API\n - Validate each clip (resolution, fps, duration)\n - Auto-retry with different seeds if failed\n\n3. Concatenation Phase\n - Pre-flight validation (ensure all clips match)\n - Apply transition effects (crossfade, motion blur)\n - FFmpeg encoding with proper codec\n - Export final video with metadata\n\n4. Quality Assurance\n - Face consistency check across clips\n - Color grading consistency\n - Audio sync validation (if applicable)\n - Generate QA report","type":"text"}]},{"type":"paragraph","content":[{"text":"Expected output:","type":"text","marks":[{"type":"strong"}]},{"text":" Single cohesive video with smooth transitions","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pipeline 2: Batch I2V Processing","type":"text"}]},{"type":"paragraph","content":[{"text":"Use when:","type":"text","marks":[{"type":"strong"}]},{"text":" You have multiple images to animate independently","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"1. Image Discovery\n - Scan directory for source images\n - Validate image specs (resolution, format)\n - Generate processing manifest\n\n2. Parallel I2V Queue\n - Queue all images to ComfyUI with appropriate prompts\n - Stagger submissions to avoid overload\n - Monitor queue depth and ETA\n\n3. Progressive Validation\n - Check each completed video immediately\n - Flag issues (wrong resolution, fps, corruption)\n - Auto-retry flagged videos\n\n4. Export & Organize\n - Move validated videos to output directory\n - Generate index with metadata\n - Create contact sheet (thumbnail preview grid)","type":"text"}]},{"type":"paragraph","content":[{"text":"Expected output:","type":"text","marks":[{"type":"strong"}]},{"text":" Directory of validated animated clips","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pipeline 3: Video Concatenation with Transitions","type":"text"}]},{"type":"paragraph","content":[{"text":"Use when:","type":"text","marks":[{"type":"strong"}]},{"text":" Combining existing video clips with professional transitions","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"1. Clip Validation\n - Verify all clips exist and are readable\n - Check resolution, fps, codec consistency\n - Report mismatches with fix suggestions\n\n2. Transition Planning\n - Detect scene changes (cut detection)\n - Recommend transition types (crossfade, zoom, pan)\n - Calculate transition timing\n\n3. FFmpeg Pipeline\n - Apply transitions between clips\n - Re-encode with consistent settings\n - Preserve quality (high bitrate, proper codec)\n\n4. Audio Handling\n - Extract audio from clips (if present)\n - Crossfade audio at transitions\n - Sync to final video timeline","type":"text"}]},{"type":"paragraph","content":[{"text":"Expected output:","type":"text","marks":[{"type":"strong"}]},{"text":" Polished video with seamless transitions","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Model Support (2026)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Image-to-Video Models","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Model","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Quality","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Speed","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"VRAM","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best For","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Notes","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"LTX-2","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"★★★★★","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"16GB+","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Production 4K video","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Native 4K, audio+video","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Wan 2.2 MoE","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"★★★★★","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Slow","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"24GB+","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Film-quality aesthetics","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"First+last frame control","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Wan 2.1 14B","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"★★★★","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Slow","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"24GB","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"High quality","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Proven, stable","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Wan 2.1 1.3B","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"★★★","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fast","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8GB","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Quick iteration","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Consumer-friendly","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"AnimateDiff V3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"★★★","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fast","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8GB","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Infinite length","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Motion LoRAs","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"SVD (Stable Video Diffusion)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"★★★","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"12GB","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Short clips","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"14-25 frames","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Transition Effects","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Effect","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Case","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Encoding Cost","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Crossfade","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"General purpose","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Low","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Motion blur","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"High-motion scenes","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Zoom in/out","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dramatic emphasis","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pan left/right","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Scene establishment","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Medium","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fade to/from black","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Chapter breaks","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Low","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom LUT","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Color grading","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Low","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"ComfyUI Instance Management","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Health Monitoring","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# Auto-detected issues:\n- Queue stalled (no progress for 5+ minutes)\n- Memory leak (VRAM usage climbing)\n- Process crashed (connection refused)\n- API unresponsive (timeout on /queue endpoint)\n- Disk full (output directory at capacity)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Auto-Recovery Actions","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"1. Soft Recovery (no restart)\n - Clear stuck queue items\n - Force garbage collection\n - Unload models from VRAM\n\n2. Hard Recovery (restart required)\n - Save current queue state\n - Kill ComfyUI process gracefully\n - Wait for port release\n - Restart with same config\n - Restore queue from saved state\n\n3. Emergency Fallback\n - Switch to backup ComfyUI instance\n - Redirect queue to instance on different port\n - Continue processing without data loss","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Multi-Instance Support","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Run multiple ComfyUI instances for parallel processing\nInstance 1: localhost:8188 (primary - I2V generation)\nInstance 2: localhost:8189 (secondary - upscaling/post-processing)\nInstance 3: localhost:8190 (backup - standby for failover)\n\n# Load balancing strategy:\n- Round-robin for equal workloads\n- Priority-based for mixed tasks\n- Failover for crashed instances","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Validation Suite","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pre-Generation Validation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"✓ Check ComfyUI is running and responsive\n✓ Verify models are loaded (UNET, VAE, CLIP)\n✓ Confirm output directory has sufficient space\n✓ Validate source images exist and are readable\n✓ Check prompts are non-empty and formatted correctly\n✓ Verify workflow JSON is valid","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Post-Generation Validation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"✓ Video file exists and is non-zero size\n✓ Resolution matches expected (e.g., 768x1024)\n✓ FPS matches expected (e.g., 16 or 25)\n✓ Duration matches expected (e.g., 3-5 seconds)\n✓ Codec is compatible (h264, h265)\n✓ No corruption (can read all frames)\n✓ Face consistency score >0.85 (if character video)\n✓ Color histogram within expected range","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Quality Metrics","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"Metrics tracked:\n- Face embedding distance (identity consistency)\n- Optical flow magnitude (motion smoothness)\n- Frame PSNR/SSIM (interpolation quality)\n- Color histogram deviation (lighting consistency)\n- Audio sync offset (if audio present)","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Error Handling & Recovery","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Retry Strategies","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"1. Seed Randomization Retry\n - Failed generation? Try different seed\n - Max 3 attempts per keyframe\n - Track seeds that fail (avoid reuse)\n\n2. Parameter Adjustment Retry\n - CFG too high causing artifacts? Lower it\n - Steps too low causing incompleteness? Increase\n - Resolution too high OOM? Downscale\n\n3. Model Fallback Retry\n - Wan 2.2 14B OOM? Fall back to 1.3B\n - LTX-2 unavailable? Fall back to Wan 2.1\n - AnimateDiff motion broken? Switch motion LoRA\n\n4. Checkpoint Resume\n - Save progress after each successful clip\n - Resume from last successful checkpoint\n - Skip already-generated clips","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Failure Logging","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"logs/\n├── 2026-02-16_pipeline.log # Main pipeline log\n├── 2026-02-16_comfyui.log # ComfyUI stdout/stderr\n├── 2026-02-16_validation.json # Validation results\n├── 2026-02-16_failures.json # Failed attempts with reasons\n└── 2026-02-16_recovery.json # Recovery actions taken","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Directory Structure","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Organized Output","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"project_name/\n├── 00_keyframes/ # Source keyframe images\n│ ├── kf01_scene_description.png\n│ ├── kf02_scene_description.png\n│ └── ...\n├── 01_clips/ # Individual animated clips\n│ ├── clip_001_kf01.mp4\n│ ├── clip_002_kf02.mp4\n│ └── ...\n├── 02_validated/ # Clips that passed validation\n│ ├── clip_001_kf01.mp4\n│ ├── clip_002_kf02.mp4\n│ └── ...\n├── 03_transitions/ # Intermediate files for transitions\n│ ├── transition_001_002.mp4\n│ └── ...\n├── 04_final/ # Final combined video\n│ ├── final_video_v1.mp4\n│ ├── final_video_v2.mp4 # After revisions\n│ └── ...\n├── logs/ # Execution logs\n├── metadata/ # JSON metadata for each asset\n└── manifest.json # Complete project manifest","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow Examples","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example 1: 30-Second Narrative Video (5 keyframes)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# Configuration\nproject_name = \"sage_character_reveal\"\nkeyframes = 5\ni2v_model = \"wan_2.2_moe\"\ntarget_duration = 30 # seconds\nfps = 16\n\n# Pipeline execution\n1. Generate 5 keyframes (IP-Adapter + LoRA)\n → sage_kf01_over_shoulder.png\n → sage_kf02_turning.png\n → sage_kf03_cardigan_fallen.png\n → sage_kf04_removing_bra.png\n → sage_kf05_topless.png\n\n2. Validate keyframes\n → Face consistency: 0.92 ✓\n → Lighting consistency: 0.88 ✓\n → Pose progression: logical ✓\n\n3. Queue I2V for each keyframe\n → clip_001: 6s @ 16fps (96 frames) ✓\n → clip_002: 6s @ 16fps (96 frames) ✓\n → clip_003: 6s @ 16fps (96 frames) ✓\n → clip_004: 6s @ 16fps (96 frames) ✓\n → clip_005: 6s @ 16fps (96 frames) ✓\n\n4. Apply 0.5s crossfade transitions\n → Total: 30s - 2s (4 transitions × 0.5s) = 28s net\n\n5. Export final video\n → sage_character_reveal_final.mp4 (30s, 768x1024, 16fps)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example 2: Batch Process 20 Images","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# Configuration\ninput_dir = \"E:/ComfyUI/input/character_expressions\"\ni2v_model = \"ltx_2\"\nmotion_prompt = \"gentle breathing, subtle movement, natural\"\nbatch_size = 4 # Process 4 at a time\n\n# Pipeline execution\n1. Scan input directory\n → Found 20 PNG files\n\n2. Queue 4 at a time to ComfyUI\n → Batch 1: expr_001.png → expr_004.png ✓\n → Batch 2: expr_005.png → expr_008.png ✓\n → Batch 3: expr_009.png → expr_012.png ✓\n → Batch 4: expr_013.png → expr_016.png ✓\n → Batch 5: expr_017.png → expr_020.png ✓\n\n3. Validate each output\n → 19/20 passed (expr_011 failed - wrong resolution)\n → Retry expr_011 with corrected settings ✓\n\n4. Export batch\n → 20 validated clips in output/expressions/\n → Generated contact sheet: expressions_preview.png","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Files","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Detailed Guides","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/keyframe-generation.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Keyframe creation with IP-Adapter, LoRA, consistency tips","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/i2v-workflows.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Wan 2.2, LTX-2, AnimateDiff, SVD workflow templates","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/concatenation.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - FFmpeg commands, transition effects, audio handling","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/validation.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Quality metrics, validation thresholds, troubleshooting","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/instance-management.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - ComfyUI health checks, restart scripts, multi-instance setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/api-reference.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - ComfyUI API endpoints, queue management, workflow submission","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/troubleshooting.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Common issues and solutions","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Integration with Other Skills","type":"text"}]},{"type":"paragraph","content":[{"text":"Pair with:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"comfyui-character-gen","type":"text","marks":[{"type":"code_inline"}]},{"text":" - For generating initial keyframes with identity preservation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"video-assembly","type":"text","marks":[{"type":"code_inline"}]},{"text":" - For advanced editing and post-production","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"youtube-uploader","type":"text","marks":[{"type":"code_inline"}]},{"text":" - For direct upload to YouTube after production","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Advanced Features","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Adaptive Quality","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# Automatically adjust settings based on available resources\nif vram_available > 24:\n use_model = \"wan_2.2_moe_14b\"\n resolution = (832, 1216)\n batch_size = 1\nelif vram_available > 12:\n use_model = \"wan_2.1_1.3b\"\n resolution = (768, 1024)\n batch_size = 2\nelse:\n use_model = \"animatediff_v3\"\n resolution = (512, 768)\n batch_size = 4","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Progress Tracking","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# Real-time progress updates\n[Pipeline] Keyframe generation: 3/5 complete (60%)\n[Pipeline] ETA: 12 minutes remaining\n[I2V] clip_003 generating: 47/96 frames (49%)\n[I2V] Current speed: 0.42 it/s\n[Validation] clip_001: PASS ✓\n[Validation] clip_002: PASS ✓","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Rollback & Versioning","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# Automatically version outputs\noutput/\n├── final_video_v1.mp4 # Initial render\n├── final_video_v2.mp4 # After fixing clip_003\n├── final_video_v3.mp4 # After adding transitions\n└── final_video_final.mp4 # Approved version\n\n# Rollback to previous version\nrollback_to_version(2) # Restore v2 as current","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow Generation","type":"text"}]},{"type":"paragraph","content":[{"text":"When asked to create a video production workflow:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Assess Requirements","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Number of shots/keyframes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Target duration per shot","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"I2V model preference","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Transition style","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Quality vs speed tradeoff","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generate Pipeline Config","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Model selection based on VRAM/quality needs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resolution and FPS settings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation thresholds","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Retry policies","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Provide Execution Scripts","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Python scripts for API submission","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"FFmpeg commands for concatenation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation checks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Recovery procedures","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Monitor & Adapt","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Track progress in real-time","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Detect failures early","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply recovery strategies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Report final metrics","type":"text"}]}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Best Practices","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"For Keyframe Videos","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use same seed across all keyframes (consistency)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"IP-Adapter weight 0.75-0.85 (strong but not rigid)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate keyframes before I2V (saves compute)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keep clips 4-8 seconds each (sweet spot)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use 0.5-1s crossfade transitions (smooth but not slow)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"For Batch Processing","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Process in small batches (4-8 at a time)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate immediately after each batch","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Save checkpoint after each successful batch","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use priority queue for important clips","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"For Instance Management","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Monitor queue depth every 30s","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Restart if no progress for 5 minutes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keep backup instance ready on different port","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Log all restart events for debugging","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Performance Optimization","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"RTX 50 Series (2026)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# ComfyUI launch flags for optimal performance\n--highvram \\\n--fp8_e4m3fn-unet \\\n--reserve-vram 7 \\\n--use-pytorch-cross-attention\n\n# Expected performance:\n- Wan 2.2 14B: ~2-3 min per 5s clip (832x1216)\n- LTX-2 4K: ~4-5 min per 5s clip (1920x1080)\n- Wan 2.1 1.3B: ~1-2 min per 5s clip (768x1024)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"AMD GPUs (ROCm)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# ComfyUI v0.8.1+ has native ROCm support\n# No special flags needed, just install ROCm drivers","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Skill Evolution","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill adapts to new I2V models and techniques. When new models release:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add model specs to ","type":"text"},{"text":"references/i2v-workflows.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create workflow template for new model","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Update model selection logic in main pipeline","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test with sample project","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Document performance characteristics","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"See ","type":"text"},{"text":"references/evolution.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for update protocol.","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"comfyui-video-production","author":"@skillopedia","source":{"stars":66,"repo_name":"comfyui-expert","origin_url":"https://github.com/mckruz/comfyui-expert/blob/HEAD/skills/comfyui-video-production/SKILL.md","repo_owner":"mckruz","body_sha256":"e1236efa01c6d005e570fecda424b3b0e20032dc343cd3965f5297e720de4d53","cluster_key":"d1a6761ea620cf4ff31cca84a56bc9ad2dda499ec46b0928dec5b5d5006cd292","clean_bundle":{"format":"clean-skill-bundle-v1","source":"mckruz/comfyui-expert/skills/comfyui-video-production/SKILL.md","attachments":[{"id":"937b9ab9-fdec-59c0-b7d3-1904e9d09131","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/937b9ab9-fdec-59c0-b7d3-1904e9d09131/attachment.md","path":"eval/EVAL.md","size":2185,"sha256":"90b6d112e26ebc333d6ecd90109c0fc252bae0c7acc95b3ba319115959970f66","contentType":"text/markdown; charset=utf-8"},{"id":"94edf038-3635-5a77-b317-6bfd86b1e78f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/94edf038-3635-5a77-b317-6bfd86b1e78f/attachment.yaml","path":"eval/benchmark.yaml","size":1304,"sha256":"bb88ba021e2e8125ebceff8d62acb2bf61f1a0fceae6a0c7df4ef0eb087fa854","contentType":"application/yaml; charset=utf-8"},{"id":"2da14cc3-9169-5e0b-bc06-c652ddb6c46e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2da14cc3-9169-5e0b-bc06-c652ddb6c46e/attachment","path":"eval/results/.gitignore","size":83,"sha256":"80890102cd6498fafa6e7ce3f85a4fd5ac87fef1376421e3dcc18888eba7a86d","contentType":"text/plain; charset=utf-8"},{"id":"5dc1c313-cf3b-5af8-ae41-7314bd87fe86","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5dc1c313-cf3b-5af8-ae41-7314bd87fe86/attachment","path":"eval/results/.gitkeep","size":0,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","contentType":"text/plain; charset=utf-8"},{"id":"989ce70d-34ac-53fa-a937-fecd2f882aa1","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/989ce70d-34ac-53fa-a937-fecd2f882aa1/attachment.sh","path":"eval/run-eval.sh","size":18242,"sha256":"4a5f64f9347e91d8bedb149ea5fd16263f0db37875164a5c584401f915567585","contentType":"application/x-sh; charset=utf-8"},{"id":"ee6f8994-d50d-51dd-801e-feeecc91ebf2","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ee6f8994-d50d-51dd-801e-feeecc91ebf2/attachment.yaml","path":"eval/test-cases.yaml","size":7621,"sha256":"77400fb1dcdb16e0b8b4e98c375e79ced3ff60fa006633e9f13d972a55a77305","contentType":"application/yaml; charset=utf-8"},{"id":"1e39e130-51ba-592d-aa37-433febe6ceff","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1e39e130-51ba-592d-aa37-433febe6ceff/attachment.yaml","path":"eval/trigger-tests.yaml","size":1855,"sha256":"e692637390fa9d7414a1bbd6e85c7507d3ebd00867b53450689d03529802c41d","contentType":"application/yaml; charset=utf-8"},{"id":"3088388d-ccaa-5ebe-8916-1ead7e5eb242","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3088388d-ccaa-5ebe-8916-1ead7e5eb242/attachment.md","path":"references/api-reference.md","size":12426,"sha256":"b16d9d601e395dcb6bf53c210f8ee6aa6549d26b7f75395420cce2cb58ec7206","contentType":"text/markdown; charset=utf-8"},{"id":"cfacfffb-47df-5978-b16f-89a669fc84a1","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/cfacfffb-47df-5978-b16f-89a669fc84a1/attachment.md","path":"references/concatenation.md","size":13515,"sha256":"8232cb0ce1b908e5b85069f7f24b8c9da6c98b4b5019ed6de097a46466a45126","contentType":"text/markdown; charset=utf-8"},{"id":"a14ab45e-0e86-5998-8f06-a9e9448ce9f3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a14ab45e-0e86-5998-8f06-a9e9448ce9f3/attachment.md","path":"references/evolution.md","size":9083,"sha256":"2372bef4a749fd86b7cbc134fce43b5d5bc726ce640b9b48c969171e50b5fd75","contentType":"text/markdown; charset=utf-8"},{"id":"9655b535-98d1-589c-a84d-ac79169aa046","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9655b535-98d1-589c-a84d-ac79169aa046/attachment.md","path":"references/instance-management.md","size":15192,"sha256":"0764f66f48b57e889b4bdd7c4d0f2c34c4cd66bb03d3a78c700a61f996439490","contentType":"text/markdown; charset=utf-8"}],"bundle_sha256":"079a5e812c02a72a1d61b0c91ba773d8db2e9714a9a3491b0fecf6e0d149d430","attachment_count":11,"text_attachments":9,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":2,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/comfyui-video-production/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"web-development","category_label":"Web"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"web-development","import_tag":"clean-skills-v1","description":"Plan and orchestrate end-to-end video production pipelines in ComfyUI with validation gates and error recovery. Handles img2vid, txt2vid, vid2vid, and multi-shot video production. Produces pipeline plans with correct step ordering (generate, validate, animate, validate, concat), model selection, retry strategies (seed randomization, parameter adjustment, model fallback), and VRAM-aware resource management. Use when asked to make a video, animate images, create a multi-shot video, set up a video pipeline, or orchestrate video production in ComfyUI. Does NOT cover still image generation, prompt writing, workflow building for non-video tasks, video editing in external tools, model training, installation, or hardware recommendations."}},"renderedAt":1782981668432}

ComfyUI Video Production Pipeline End-to-end video production orchestration for ComfyUI with automatic error recovery, quality validation, and instance management. Quick Start: Which Pipeline? Creating a multi-shot narrative video? → Keyframe Pipeline - Generate keyframes → Animate → Stitch with transitions Animating existing images? → I2V Batch Pipeline - Load images → Queue I2V jobs → Auto-validate → Combine Need smooth transitions between scenes? → Transition Pipeline - Crossfades, motion blur, zoom effects via FFmpeg ComfyUI stuck or crashed? → Instance Manager - Auto-restart, health chec…