meta-short-drama
End-to-end short-drama generator with an explicit-consent review flow before
any paid external-media step. 1-10 shots (default 5), title card + ending
card, in-language burned subtitles, and the generated script is saved to disk
regardless of outcome. A direct approval continues immediately; an edit only
produces a revised preview and requires a second explicit approval.
What it does
intake_extract scans the user message for RENDER_STYLE,
IDENTITY_ANCHOR, and N_SHOTS (1-10). Fills in defaults when missing.
script_draft calls ai-video-script with the inferred values
pasted verbatim into every shot prompt.
review_gate — free-form draft review. The user can approve,
request changes to render style / character / shot count / shot details,
or cancel in plain language.
review_intent is local and deterministic. Explicit approval may
proceed, while a recognizable adjustment emits DECISION: revise; the
adjustment never authorizes an external call.
script_revised (conditional) applies requested overrides, then
revision_confirm_gate shows the revised preview and requires a new
explicit approval. review_normalize is the final paid-media consent
authority; cancel, missing, ambiguous, off-topic, and further-edit replies
fail closed without provider calls.
final_script freezes the canonical scheduler snapshot in memory; it
never re-reads the user-editable artifact.
script_save writes that same canonical content to script.txt in the run folder
(always — even on cancel, so the user keeps the draft).
title_extract / subtitle_extract / ending_text_extract
pull cover/ending text in the script's language.
cover_image + cover_video — Pillow title card + 2s Ken-Burns
clip (0_cover.mp4 — sorts first in merge).
- Per-shot extracts × 10 — all slots are declared, but an exact
=== SHOT_N === header check deterministically skips absent script blocks
before calling the LLM. Active extracts still use __SHOT_ABSENT__ as a
second fail-closed guard, and paid image/video steps repeat the exact-header
check so an LLM cannot activate an unused slot.
- Image generation per active shot —
nano-banana-pro, at most one paid
submit, followed by a local placeholder PNG on a verified policy refusal
(the image step never aborts the DAG). Provider responses and ambiguous
transport outcomes never trigger an automatic second paid request.
reference_prompt_extract + reference_image — one extra
nano-banana-pro call produces reference.png, a full-cast neutral
lineup of every named character on a neutral backdrop. Used as the
universal IDENTITY anchor for every shot's seedance call so the
character does not drift across cuts (nano-banana would otherwise
re-roll subtly different character designs per shot).
- Video generation per active shot —
seedance-2.0; paid submit
failures are never retried automatically because an ambiguous response may
already represent a billed job. After a job id is issued, transient polling
failures may retry that same job up to the configured limit. Any provider-policy
refusals stop immediately without another paid submission. The Ken-Burns
substitute then fires using the
shot's PNG. Each shot passes TWO reference images to seedance,
AND the per-shot prompt is wrapped with an explicit "Assets
Mapping" preamble in the upstream JiMeng convention so seedance
knows the role of each reference:
reference[1] = reference.png (full-cast fictional design anchor —
preserves silhouette / hairstyle / costumes /
accessories without reproducing real-person likeness)
reference[2] = N_shot.png (this shot's scene composition
reference — used for camera angle, framing,
blocking, prop placement, background layout)
The Assets Mapping preamble is in English even when the per-shot
directive is Chinese — seedance parses English instruction prefixes
reliably regardless of the user-content language. Empty / missing
references are still filtered before the API call (so direct CLI
callers using a single anchor remain backwards-compatible).
ending_image + ending_video — Pillow "完" / "THE END" card
- 2s Ken-Burns clip (
99_ending.mp4 — sorts last).
merge — video-merger stitches 0_cover + active shots
99_ending via numeric-prefix sort. ffmpeg cross-fade transitions.
subtitles_srt — SRT cues from VOICEOVER per shot, shifted by
the 2-second cover duration so cue timing matches the merged
timeline.
subtitled_final — subtitle-burner burns the SRT into
final_subtitled.mp4.
publish_final_video + publish_script — register the final
MP4 (video/mp4) and script (text/plain) with the active surface
so browser users receive artifact controls instead of only a local
path. The script is published even when the user cancels; the video
is published only after a successful proceed path.
delivery_audit — deterministic receipt/fallback/ffprobe gate.
It combines validated receipts with the scheduler's bounded, parent-owned
paid-submission dispositions (safe_no_submit, maybe_accepted, or
receipt; only a conclusive receipt becomes confirmed). It is the sole
authority for API provenance and reports both story content duration and
the probed final duration (content + 4s bookends). A fallback after a
proven pre-submit failure does not trigger a billing warning; ambiguous
submission outcomes still emit only a sanitized asset list and
check-history warning.
deliver — always runs, branches on DECISION, and waits for
the deterministic audit before composing delivery. It only restates
the machine-owned verdict and cannot promote fallback media to a
verified real-API result.
Outputs
<workspace>/meta_short_drama/<meta_run_id>/
script.txt # full final script (always; published artifact)
reference.png # full-cast identity reference (used by every shot_video)
0_cover.png 0_cover.mp4
1_shot.png 1_shot.mp4 ┐
2_shot.png 2_shot.mp4 ├ only for active shots (1..N_SHOTS)
... ┘
*.png.receipt.json # image provider/request or placeholder status
*.mp4.receipt.json # video provider/model/job status
99_ending.png 99_ending.mp4
subs.srt
final.mp4 # merged, no subtitles
final_subtitled.mp4 # subtitled — published video deliverable
Dependencies
| Skill |
Purpose |
Models / Tools |
ai-video-script |
Structured shot list (1-10 shots) |
LLM |
short-drama-review-normalizer |
Local fail-closed review/consent decision |
Python stdlib |
nano-banana-pro |
Per-shot first-frame PNG |
OpenRouter Gemini 3.1 / 3 pro |
seedance-2-prompt |
Per-shot MP4 |
OpenRouter Seedance 2.0 (or Volcengine ARK) |
video-still-animator |
Ken-Burns fallback / cover & ending clips |
ffmpeg ≥ 5.0 |
video-merger |
Stitch cover + shots + ending |
ffmpeg ≥ 5.0 |
srt-from-script |
VOICEOVER → SRT with cover offset |
Python stdlib |
subtitle-burner |
Burn SRT into MP4 |
ffmpeg + libass |
title-card-image |
Pillow cover + ending PNG cards |
Pillow |
(builtin) write_file |
Save script.txt (no skill needed) |
OpenSquilla builtin |
text-file-read |
Re-read script.txt after review pause |
Python stdlib |
Environment:
OPENROUTER_API_KEY must be set.
ffmpeg and ffprobe on PATH.
- Pillow installed (already in opensquilla deps).
Risk
high — writes files, spends real OpenRouter credits, runs ffmpeg
subprocesses. The review gate plus deterministic normalizer ensures explicit
approval or a meaningful requested adjustment before any external media step.
Limits (v2)
- 1-10 shots; default 5. The DAG always declares 10 slots but
__SHOT_ABSENT__ gating keeps unused slots dormant.
- Per-shot duration follows the script's DURATION_S (clamped 3-15s by
seedance API). OVERVIEW.DURATION_S means story-shot content duration;
the final MP4 adds a fixed 2s title + 2s ending (content + 4s).
- 9:16 portrait.
- Per-shot seedance failures fall back to Ken-Burns. Image step
has its own placeholder fallback. Both are explicitly reported as
degraded and cannot satisfy the verified-real-API E2E status.
Prompt-extract llm_chats still abort the run if they return malformed
output.
- Every run uses its runtime-owned
meta_run_id subdirectory, so concurrent
runs and post-review additional_notes cannot redirect or collide outputs.
When NOT to use
- Single image / single clip / script-only / stitch-only — use the
underlying skills directly.
1---2name: meta-short-drama3description: Create a complete AI short-drama package from a topic: shot script, review/approval pause, consistent images and clips, titles, subtitles, and final delivery. Do not use for isolated script or image requests, slides, document analysis, or historical examples.4---56# meta-short-drama78End-to-end short-drama generator with an explicit-consent review flow before9any paid external-media step. **1-10 shots** (default 5), title card + ending10card, in-language burned subtitles, and the generated script is saved to disk11regardless of outcome. A direct approval continues immediately; an edit only12produces a revised preview and requires a second explicit approval.1314## What it does15161. **`intake_extract`** scans the user message for RENDER_STYLE,17 IDENTITY_ANCHOR, and N_SHOTS (1-10). Fills in defaults when missing.182. **`script_draft`** calls `ai-video-script` with the inferred values19 pasted verbatim into every shot prompt.203. **`review_gate`** — free-form draft review. The user can approve,21 request changes to render style / character / shot count / shot details,22 or cancel in plain language.234. **`review_intent`** is local and deterministic. Explicit approval may24 proceed, while a recognizable adjustment emits `DECISION: revise`; the25 adjustment never authorizes an external call.265. **`script_revised`** (conditional) applies requested overrides, then27 **`revision_confirm_gate`** shows the revised preview and requires a new28 explicit approval. **`review_normalize`** is the final paid-media consent29 authority; cancel, missing, ambiguous, off-topic, and further-edit replies30 fail closed without provider calls.316. **`final_script`** freezes the canonical scheduler snapshot in memory; it32 never re-reads the user-editable artifact.337. **`script_save`** writes that same canonical content to `script.txt` in the run folder34 (always — even on cancel, so the user keeps the draft).358. **`title_extract` / `subtitle_extract` / `ending_text_extract`**36 pull cover/ending text in the script's language.379. **`cover_image` + `cover_video`** — Pillow title card + 2s Ken-Burns38 clip (`0_cover.mp4` — sorts first in merge).3910. **Per-shot extracts × 10** — all slots are declared, but an exact40 `=== SHOT_N ===` header check deterministically skips absent script blocks41 before calling the LLM. Active extracts still use `__SHOT_ABSENT__` as a42 second fail-closed guard, and paid image/video steps repeat the exact-header43 check so an LLM cannot activate an unused slot.4411. **Image generation per active shot** — `nano-banana-pro`, at most one paid45 submit, followed by a local placeholder PNG on a verified policy refusal46 (the image step never aborts the DAG). Provider responses and ambiguous47 transport outcomes never trigger an automatic second paid request.4812. **`reference_prompt_extract` + `reference_image`** — one extra49 `nano-banana-pro` call produces `reference.png`, a full-cast neutral50 lineup of every named character on a neutral backdrop. Used as the51 universal IDENTITY anchor for every shot's seedance call so the52 character does not drift across cuts (nano-banana would otherwise53 re-roll subtly different character designs per shot).5413. **Video generation per active shot** — `seedance-2.0`; paid submit55 failures are never retried automatically because an ambiguous response may56 already represent a billed job. After a job id is issued, transient polling57 failures may retry that same job up to the configured limit. Any provider-policy58 refusals stop immediately without another paid submission. The Ken-Burns59 substitute then fires using the60 shot's PNG. Each shot passes TWO reference images to seedance,61 AND the per-shot prompt is wrapped with an explicit "Assets62 Mapping" preamble in the upstream JiMeng convention so seedance63 knows the role of each reference:64 reference[1] = `reference.png` (full-cast fictional design anchor —65 preserves silhouette / hairstyle / costumes /66 accessories without reproducing real-person likeness)67 reference[2] = `N_shot.png` (this shot's scene composition68 reference — used for camera angle, framing,69 blocking, prop placement, background layout)70 The Assets Mapping preamble is in English even when the per-shot71 directive is Chinese — seedance parses English instruction prefixes72 reliably regardless of the user-content language. Empty / missing73 references are still filtered before the API call (so direct CLI74 callers using a single anchor remain backwards-compatible).7513. **`ending_image` + `ending_video`** — Pillow "完" / "THE END" card76 + 2s Ken-Burns clip (`99_ending.mp4` — sorts last).7714. **`merge`** — `video-merger` stitches `0_cover` + active shots78 + `99_ending` via numeric-prefix sort. ffmpeg cross-fade transitions.7915. **`subtitles_srt`** — SRT cues from VOICEOVER per shot, shifted by80 the 2-second cover duration so cue timing matches the merged81 timeline.8216. **`subtitled_final`** — `subtitle-burner` burns the SRT into83 `final_subtitled.mp4`.8417. **`publish_final_video` + `publish_script`** — register the final85 MP4 (`video/mp4`) and script (`text/plain`) with the active surface86 so browser users receive artifact controls instead of only a local87 path. The script is published even when the user cancels; the video88 is published only after a successful proceed path.8918. **`delivery_audit`** — deterministic receipt/fallback/ffprobe gate.90 It combines validated receipts with the scheduler's bounded, parent-owned91 paid-submission dispositions (`safe_no_submit`, `maybe_accepted`, or92 `receipt`; only a conclusive receipt becomes `confirmed`). It is the sole93 authority for API provenance and reports both story content duration and94 the probed final duration (content + 4s bookends). A fallback after a95 proven pre-submit failure does not trigger a billing warning; ambiguous96 submission outcomes still emit only a sanitized asset list and97 check-history warning.9819. **`deliver`** — always runs, branches on DECISION, and waits for99 the deterministic audit before composing delivery. It only restates100 the machine-owned verdict and cannot promote fallback media to a101 verified real-API result.102103## Outputs104105```106<workspace>/meta_short_drama/<meta_run_id>/107 script.txt # full final script (always; published artifact)108 reference.png # full-cast identity reference (used by every shot_video)109 0_cover.png 0_cover.mp4110 1_shot.png 1_shot.mp4 ┐111 2_shot.png 2_shot.mp4 ├ only for active shots (1..N_SHOTS)112 ... ┘113 *.png.receipt.json # image provider/request or placeholder status114 *.mp4.receipt.json # video provider/model/job status115 99_ending.png 99_ending.mp4116 subs.srt117 final.mp4 # merged, no subtitles118 final_subtitled.mp4 # subtitled — published video deliverable119```120121## Dependencies122123| Skill | Purpose | Models / Tools |124|---|---|---|125| `ai-video-script` | Structured shot list (1-10 shots) | LLM |126| `short-drama-review-normalizer` | Local fail-closed review/consent decision | Python stdlib |127| `nano-banana-pro` | Per-shot first-frame PNG | OpenRouter Gemini 3.1 / 3 pro |128| `seedance-2-prompt` | Per-shot MP4 | OpenRouter Seedance 2.0 (or Volcengine ARK) |129| `video-still-animator` | Ken-Burns fallback / cover & ending clips | ffmpeg ≥ 5.0 |130| `video-merger` | Stitch cover + shots + ending | ffmpeg ≥ 5.0 |131| `srt-from-script` | VOICEOVER → SRT with cover offset | Python stdlib |132| `subtitle-burner` | Burn SRT into MP4 | ffmpeg + libass |133| `title-card-image` | Pillow cover + ending PNG cards | Pillow |134| (builtin) `write_file` | Save script.txt (no skill needed) | OpenSquilla builtin |135| `text-file-read` | Re-read script.txt after review pause | Python stdlib |136137Environment:138- `OPENROUTER_API_KEY` must be set.139- `ffmpeg` and `ffprobe` on PATH.140- Pillow installed (already in opensquilla deps).141142## Risk143144`high` — writes files, spends real OpenRouter credits, runs ffmpeg145subprocesses. The review gate plus deterministic normalizer ensures explicit146approval or a meaningful requested adjustment before any external media step.147148## Limits (v2)149150- 1-10 shots; default 5. The DAG always declares 10 slots but151 `__SHOT_ABSENT__` gating keeps unused slots dormant.152- Per-shot duration follows the script's DURATION_S (clamped 3-15s by153 seedance API). OVERVIEW.DURATION_S means story-shot content duration;154 the final MP4 adds a fixed 2s title + 2s ending (content + 4s).155- 9:16 portrait.156- Per-shot seedance failures fall back to Ken-Burns. Image step157 has its own placeholder fallback. Both are explicitly reported as158 degraded and cannot satisfy the verified-real-API E2E status.159 Prompt-extract llm_chats still abort the run if they return malformed160 output.161- Every run uses its runtime-owned `meta_run_id` subdirectory, so concurrent162 runs and post-review `additional_notes` cannot redirect or collide outputs.163164## When NOT to use165166- Single image / single clip / script-only / stitch-only — use the167 underlying skills directly.