Loading...
Loading...
One-shot autopilot orchestrator — runs the full spark-video pipeline (screenwriter ↔ director per-scene parallel → render chain-DAG parallel + per-clip review → stitch). User confirms at 4 gates (+ 1 mode gate at start + 1 BGM gate when bgm/ folder detected). Use when the user wants "make me an episode" in one command.
npx skill4agent add modelstudioai/skills spark-video-episodespark-video-screenwriterspark-video-directorspark-video-vfx-reviewspark-video-clip-reviewspark-video-castscripts/export SPARK_VIDEO_PROJECT=<project_id>
export SPARK_VIDEO_EPISODE=<NN>
export SPARK_VIDEO_PHASE=producer
# SPARK_VIDEO_PROVIDER defaults to "bl"; only set if user opted for wan27hfdemo001projects/<p>/initialPrompt.mdprojects/<p>/<ep>/premise.mdviewer.html--vfx--mode=drama|narration--provider=bl|wan27| Gate | When | What you show | What you ask |
|---|---|---|---|
| GATE 0 | Before any work, unless | One-paragraph explainer of drama vs narration mode | "Drama (短剧, default) or Narration (旁白解说)?" |
| GATE 0.5 | After GATE 0, only if | List of available BGM tracks | "How should I use BGM? (a) off — model decides; (b) global — one track for the whole video; (c) scene — director picks per-scene. Also: forbid the video model from generating its own BGM? (default: yes)" |
| GATE 1 | After screenwriter finishes all scenes/scene-NN.md and you've compiled into | The merged | "剧本 OK 吗? Approve to proceed to storyboarding, or describe changes." |
| GATE 2 | After director finishes all scenes/scene-NN.json and you've compiled+validated into | | "分镜 OK 吗? Approve to render, or describe changes." |
| GATE 3 | After all shots rendered + reviewed (winner_version set for each, escalations resolved) | Per-shot summary (winner version, best score, any that fell below threshold accepted-anyway) | "渲染 OK 吗? Approve to stitch final, or specify shots to re-render." |
| GATE 4 | After stitch completes | Path to | "OK to finalize? Want to re-render any shots or adjust BGM mix?" |
╔══════════════════════════════════════════╗
║ YOU (spark-video-episode / producer) ║
╚══════════════════════════════════════════╝
│
[GATE 0: mode]
│
[GATE 0.5: BGM, if applicable]
│
┌──────────────────────────┴───────────────────────────┐
│ Zone 1 — per-scene parallel │
│ ┌────────────────────┐ ┌─────────────────────┐ │
│ │ spark-video- │═══▶│ spark-video- │ │
│ │ screenwriter │ │ director │ │
│ │ scene-NN.md │ │ scene-NN.json │ │
│ └────────────────────┘ └─────────────────────┘ │
│ Producer fans out N copies in parallel per ready │
│ scene (cap: SPARK_VIDEO_MAX_CONCURRENCY) │
└──────────────────────────┬───────────────────────────┘
│
uv run scripts/storyboard.py compile
│
[GATE 1: script.md]
│
[GATE 2: storyboard.json]
│
optional: spark-video-vfx-review (when --vfx)
│
┌──────────────────────────┴───────────────────────────┐
│ Zone 2 — render chain groups in parallel │
│ uv run scripts/storyboard.py graph │
│ → [[S01-001,S01-002], [S02-001], ...] │
│ Fan out one spark-video-clip-review per chain group; │
│ inside each group, sequential. │
│ │
│ Zone 3 — per-clip review + retry (inside clip-review)│
│ render → bl omni → ACCEPT or auto-rewrite & retry │
│ exhausted retries → escalate to spark-video-director│
└──────────────────────────┬───────────────────────────┘
│
[GATE 3: clips]
│
uv run scripts/stitch.py
│
[GATE 4: final mp4]./scripts/doctor.sh # bl + ffmpeg + uv present
uv run scripts/scaffold.py episode --init # mkdir scaffold if not exists
# Persist the user's raw premise to disk BEFORE any other work. This is
# the single source of truth for "what did the user actually ask for?"
# and is read back by scripts/build_viewer.py to populate the Premise
# section of viewer.html. Without this file viewer.html will show
# "(no initialPrompt.md / premise.md found …)" forever.
# Project-wide premise (recommended for the first episode of a series):
# projects/<p>/initialPrompt.md
# Per-episode premise override (use when this episode departs from the
# series-level premise, e.g. a spin-off or recap):
# projects/<p>/<ep>/premise.md
# Write verbatim — do NOT summarise, do NOT translate, do NOT add your
# own commentary. The whole point is auditability.
premise_path="projects/$SPARK_VIDEO_PROJECT/initialPrompt.md"
if [ ! -s "$premise_path" ]; then
mkdir -p "$(dirname "$premise_path")"
cat > "$premise_path" <<'PREMISE_EOF'
<paste the user's premise here, verbatim, including any constraints,
references, character names, tone notes — anything they said about
what they want this episode to be>
PREMISE_EOF
fi
# Check lore.md exists; if not:
test -f projects/$SPARK_VIDEO_PROJECT/lore.md || \
uv run scripts/scaffold.py lore --title "<premise's first noun phrase>"
# Tell user lore.md was scaffolded with mood_anchor=TBD; ask to fill it
# OR auto-fill it from the premise using bl text chat--mode--mode <choice>test -d projects/$SPARK_VIDEO_PROJECT/bgm || \
test -d projects/$SPARK_VIDEO_PROJECT/episode-$SPARK_VIDEO_EPISODE/bgm || skip
ls projects/$SPARK_VIDEO_PROJECT{,/episode-$SPARK_VIDEO_EPISODE}/bgm/*.{mp3,wav,m4a,flac,ogg,aac} 2>/dev/nullmodeforbid-model-bgmprojects/<p>/<ep>/bgm-config.jsonStoryboard.bgmuv run scripts/scaffold.py cast-init # build cast.json
uv run scripts/scaffold.py set-init # build movie_set.json
uv run scripts/scaffold.py prop-init # build props.jsonspark-video-castscene-NN.mdscene-NN.readySPARK_VIDEO_MAX_CONCURRENCY=4uv run scripts/storyboard.py compile --mode <drama|narration>
uv run scripts/storyboard.py validate
uv run scripts/storyboard.py graph
uv run scripts/storyboard.py estimatescript.mdstoryboard.py graphstoryboard.py estimateSPARK_VIDEO_LONG_CONFIRM_S--vfxspark-video-vfx-reviewspark-video-directoruv run scripts/storyboard.py graph
# → [["S01-001","S01-002"], ["S02-001"], ...]spark-video-clip-reviewSPARK_VIDEO_MAX_CONCURRENCYneeds_director_rewrite.jsonspark-video-director--force --reset-attemptslogs/model_calls.jsonltail -f projects/<p>/<ep>/logs/model_calls.jsonl | jq .shots_state.jsonwinner_versionwinner_versionjq '.[] | {shot: .shot_id, ver: .winner_version,
score: ([.attempts[]|.review.score]|max),
below_threshold: ((.attempts[]|.review.score|select(.<7))!=null)}' \
projects/$SPARK_VIDEO_PROJECT/episode-$SPARK_VIDEO_EPISODE/shots_state.jsonuv run scripts/stitch.py --crossfade 0.5stitch.pyclips/<shot>.mp4bl speech synthesizeStoryboard.bgm.trackprojects/<p>/<ep>/final/<p>-<ep>.mp4| Var | Default | Meaning |
|---|---|---|
| | |
| | Parallel chain groups / subagents |
| | ACCEPT cutoff for clip-review |
| | Retry rounds per shot before escalation |
| | Estimate exit-2 threshold (seconds of rendered video) |
| | Narration TTS via bl |
| | Default narrator voice |
| | Default speech rate (0.5–2.0) |
spark-video-screenwriteruv run scripts/render_shot.py --shot S03-002 --force --reset-attemptsStoryboard.bgm.volumebgm-config.jsonuv run scripts/stitch.py--vfx--mode--providerstoryboard.py validatestoryboard.py estimatebl./scripts/bllogs/model_calls.jsonlneeds_director_rewrite.jsonspark-video-directorSPARK_VIDEO_MAX_CONCURRENCYscript.mdstoryboard.jsonuv run scripts/storyboard.py compileprojects/<p>/initialPrompt.mdprojects/<p>/<ep>/premise.mdviewer.html