What does AI Documentary Production do?
First Use: Environment Setup
- Images: By default, the user generates images with GPT; AI does not call image APIs;
image_mode=agentrequires explicit approval. - Environment: Python 3.10+,
ffmpeg,ffprobe;contact_sheet.pyadditionally requires Pillow; no PyYAML dependency. - H3: If you haven't configured MiniMax H3, first check
references/00_setup.md:- Register/verify identity/recharge on the open platform;
- Create an API Key;
- Set the
MINIMAX_API_KEYenvironment variable or use a key file; - Align
base_url/ model name / resolution; - Run a 4-second test first, then batch.
- Keys should never be included in code, logs, or git.
- If H3 is unavailable, switch providers or create an animatic first; do not pretend to generate.
- If H3 is not configured, do not proceed to G5.
When to Use
- User wants to create a character/theme short film, with duration determined by the brief;
- 30 seconds, 1 minute, 3 minutes are just examples, not hard limits;
- Involves real people, historical materials, AI reenactments;
- Needs to go from zero to a deliverable finished film;
- Requires cost control, source retention, and credits writing.
Not Applicable
- Multi-character portraits, interview-style feature films;
- Commercial advertisements, pure product videos;
- Full animation, full virtual production;
- On-site documentaries requiring real filming.
Duration has no hard threshold; extra-long projects require additional asset management, but the workflow remains the same.
Must Ask Before Starting
- Finished film duration, aspect ratio, frame rate, language, platform;
- Who is the character, which part of the story, which facts cannot be wrong;
- Budget ceiling, whether retries are allowed;
- Who generates images (
image_mode=human/agent), which video model, which editing software; - Whether narration is real voice or TTS; whether music is a separate track;
- Whether historical photos/music licenses exist; whether an AI disclaimer is needed;
- Delivery format and deadline;
- Profile:
short(approx. 15–60s) /standard(approx. 2–5min) /custom(as needed); model_routing:hybrid/gpt_only/codex_deepseek;- Whether H3 is configured (Key/base_url/model/quota); if not, teach configuration first;
- Opening card:
none/static; how many seconds; whether it counts toward the target duration; title text to be finalized at G2.5.
Without a brief, do not proceed to research.
Duration and Profile
Duration is determined by duration_target_sec in project.yaml, not hardcoded.
| profile | example duration | shots (example) | segments (example) | music (example) |
|---|---|---|---|---|
| short | 15–60s | 8–18 | 1–2 | 1 segment |
| standard | 2–5min | 24–60 | 3–5 | 3–5 segments |
| custom | user-defined | user-defined | user-defined | user-defined |
These are estimates, not gates; 30 seconds and 3 minutes are just two common examples.
G4 Image Handoff
After prompts are completed, first remind the user to generate images, then work in parallel:
- Send
image_batch_request.md: shot number, filename, prompt location, quantity, priority; if opening card is enabled,0-1_card.pnggoes into the first batch; - State clearly: "You can start generating images now";
- Once the user starts, the agent does work that does not depend on images/video: subtitles, cue sheet, cost table, sources/credits, editing skeleton, QA for next batch of prompts;
- Do not review images, generate video, or do final compositing;
- After the user returns images, review them first; do not re-discuss already locked narration/shots;
- Opening card is a static card, do not use H3; verify text character by character; if Chinese is unstable, switch to post-production overlay.
Do not silently work on other things and keep the user waiting; the image generation task must be handed off first. See
references/13_parallel_work.mdfor details.
Model Routing
Default is hybrid:
| Stage | Model | Task |
|---|---|---|
| G0–G3 | Codex + DeepSeek | brief, research, narration, storyboard, prompts |
| G4 | GPT | generate/review images; image_mode determines who generates |
| G5–G8 | Codex + DeepSeek | tasks, costs, editing files, QC; temporarily switch to GPT when reviewing images |
- Use DeepSeek for text and files, GPT for pixels and visuals;
image_mode=human: user generates with GPT;image_mode=agent: Codex + image tools generates (requires explicit approval);- Write
image_handoff.mdbefore switching; project files serve as handoff credentials; - See
references/10_model_routing.mdfor details.
9 Stages and G0–G8 Gates
| Stage | Deliverable | Gate |
|---|---|---|
| G0 Brief | project_brief.md | Duration, budget, rights, platform locked |
| Research/Fact Check | fact_check.csv, research.md | G1 Facts locked |
| Script/Narration | script.md, vo.csv, vo_text_review.md, voice_audition.md, vo_lock.md, vo_review.md | G2 Narration locked (copy + voice + version) |
| Storyboard/Timeline | beats.csv, shots.csv, segments.csv, timeline.csv, animatic.mp4, v0_review.md | G3 Beats claimed + shot table + v0 confirmed |
| First Frames (per image_mode) | first_frames/, image_review.md, image_handoff.md, image_batch_request.md | G4 First frames locked |
| Video Generation | h3_package/, clips/, tasks.json, cost.csv | G5 Video locked |
| Rough Cut/Subtitles | cut/, subtitles.srt | G6 Picture locked |
| Music/Sound | music/, cue_sheet.csv | G7 Sound locked |
| Final QC/Delivery | final.mp4, final_qc.md, credits.md | G8 Delivery |
Rule: Do not proceed to the next gate until the current one is passed; do not spend money.
Opening Card
Only ask at G0: "Do you want one, how many seconds, does it count toward the target duration"; title text is finalized at G2.5.
- G0:
opening_card: none|static;opening_seconds;opening_in_target; - G2.5: Main title/subtitle/font style;
opening_card.mdcharacter-by-character confirmation; - G3: Written as a
0-1static shot inshots.csv(static=yes, no narration), aCARDrow insegments.csv(static=yes); - G4: Goes into the first image batch, filename
first_frames/0-1_card.png; verify text character by character when images come out; - G5: Do not use H3;
export_h3.pyskipsstatic=yes; do not include it in the H3 task table; - G6: Static hold in editing; can apply a slow 1–2% push-in;
- Opening card duration is deducted from the target duration or explicitly added to the total length, decided at G0.
The opening card is a "duration decision during project initiation", not a "decoration option when generating images".
Narration Review Order
- Copy Review: Show the user the full
vo.csv, timecodes, and fact notes; get user confirmation before doing voice; - Voice Audition: Generate 2–3 candidates for the same sentence, let the user choose A/B/C or record their own;
- Full Scratch: Generate the complete narration with the chosen voice;
- v0 Animatic: Only then create static frames + narration;
- Do not proceed to the next step without confirmation at any step.
Narration First
This is the core sequence of the skill:
- Finalize narration first, then shots, first frames, video;
- One narration line matches 2–3 shots as the norm;
- One shot per line is a special case (short reaction, slogan, single-shot montage), not the default;
- Narration stands independently as
vo.csv, do not fragment by shot; - Do not generate TTS per shot; generate per sentence/paragraph, place the entire segment on one audio track;
- Each sentence carries one piece of information; every 1–2 sentences contains at least one hard fact (year/person/number/action/cause-effect);
- Poetic imagery must have a concrete anchor, a chain, and be grounded; "door/seed" can be a motif, not an automatic error; anchorless slogans are empty words; explain cause and effect first, then poetic language;
- After writing, run
narration_lint.py, then read once to finalize; - When editing, use J-cut/L-cut: picture cuts, narration continues;
- Leave 0.3–1.0 seconds of breathing room between sentences; do not force a 5-second narration onto a 5-second shot; it is best to bear the breathing room with a short shot without narration, not inside a shot with narration;
- Breathing room should only be placed between narration sentences; cut points must fall within the breathing room, not inside a sentence with narration;
- After narration is locked, do not directly modify the old version; first run
vo_diff.py, only change affected files; - One narration segment can span multiple shots; a normal shot should have at most one narration segment; a
long_take=yesshot can contain multiple narration segments, but each must be completely within the shot; - The breathing room window between adjacent narrations must contain at least one shot cut point; sentence start/end can fall inside the shot, not required to align with the cut point; when there is a range, use the larger breathing room;
- After finishing
shots.csv/timeline.csv, first produce a v0 animatic (static/black frames + narration), explicitly remind the user to listen for breathing room between sentences; confirm before proceeding to first frames/video; - Show the copy first, then determine the voice, then make v0: without user confirmation of copy and voice, do not generate TTS/animatic.
First the narration, then the visuals; not 40 shots first, then cram a sentence into each one.
File Contracts
shots.csv
id,story_segment,scene_id,duration,shot_size,camera,scene,action,expression,vo_ids,anchor,first_frame,video,status,cost,notes,long_take,static
story_segmentis the narrative segment number, not the H3 generation segment; generation segments are insegments.csvundergeneration_id;scene_idis the scene number, must matchsegments.csv;durationin seconds, supports decimals;statusonly usestodo/image_ready/video_running/video_ok/conditional/retake/final;vo_idscan be empty; a normal shot should have at most one vo_id; along_take=yesshot can writeV01|V02;long_take=yes: one continuous long take, allows 2+ narration segments, but each must be completely within the shot;static=yes: static opening card/insert card, do not use H3; must have afirst_frame, use astatic=yessegment insegments.csv;- This is the source of truth for visuals; narration is in
vo.csv, linked viavo_ids.
vo.csv
vo_id,start,end,text,shot_ids,notes
V01,0.0,4.2,"A complete narration line","1-1|1-2","4.2s; 0.8s breathing room after"
V02,5.0,6.2,"Next line","1-3","1.2s; 0.8s at the end"
start/endare absolute seconds;- One narration line can span 2–3 shots;
- One shot per line is only used in special cases;
- Leave 0.3–1.0 seconds of breathing room between sentences;
- One
shot_idcan belong to only one cue; one cue can cover multiple shots; - Subtitles are generated from
vo.csv, not bound to shots.
beats.csv
beat_id,story_segment,kind,shot_id,vo_id,text,notes
B01,1,action,1-1,V01,Calculating behind the counter,
B02,1,action,2-1,V02,Putting the paper into an envelope,
- A beat is the smallest unit of story, not a musical beat;
- Each beat is exactly claimed by one
shot_id; - Each non-
staticshot has at least one beat;static=yesopening cards can have no beat; each narration segment has at least one beat; - One narration can span multiple beats, repeating the same
vo_idon each row; - Beat order must be consistent with shot order; missing, duplicate, or out-of-order beats are caught by
validate.py.
segments.csv
generation_id,scene_id,cut_order,shot_id,start,end,duration,keyframe,static,notes
S01,1,1,1-1,0,5,5,first_frames/1-1_first.png,no,single-cut segment
S02,1,1,1-2,5,9,4,first_frames/1-2_first.png,no,cut 1 within segment
S02,1,2,1-3,9,15,6,first_frames/1-3_first.png,no,cut 2 within segment
generation_id= one H3 generation; a segment ≤15 seconds, does not cross scenes;scene_idmust equal thescene_idof the same shot inshots.csv; scene change requires a new segment;cut_order= the cut order within the segment, starting from 1 sequentially;keyframe= composition anchor image for this cut; cut 1 pins at 0.00 seconds, subsequent cuts pin at the cut point;static=yes= static card, not for H3; must be a single cut;export_h3.pywill skip;- Each shot can only appear in one generation;
- Each cut's
start/end/durationmust equal the cumulative start and end inshots.csv; the entire film must have no gaps and no overlaps; validate.pycatches overruns, misalignments, gaps, and duplicates.
h3_prompts.csv
shot_id,prompt,soundscape,notes
1-1,"Maintain the first frame; the pen tip moves slowly, the lamp flame sways gently.","Sound of paper and pen, distant wind.",
export_h3.pygroups bysegments.csvand stitches each cut's prompt into a multi-image alignment prompt;- Outputs
h3_package/<generation_id>/prompt.md+manifest.json; - Does not call APIs; generation is still executed by the H3 task table.
Narration Versions
vo_versions/vo_v1.csv
vo_v1_scratch.wav
vo_lock.md
- Before locking, do a read-through/TTS, measure actual duration;
- After locking, only add new versions, do not directly modify the old version;
- To change narration, first run
vo_diff.py, then modify affected files; - See
references/12_change_control.mdfor details.
project.json
Machine configuration generated by init_project.py: profile/model_routing/image_mode/duration_target_sec/shot_target/fps/resolution/providers.
project.yaml is the human-readable version; scripts read project.json.
tasks.json
[{"generation_id":"S01","provider":"minimax_h3","model":"MiniMax-H3","resolution":"768P","duration":9,"status":"todo","prompt":"h3_package/S01/prompt.md","first_frames":["first_frames_h3/1-1_first.png"],"cost_cny":0.0}]
generation_idcorresponds to the generation segment insegments.csv;durationmust be an integer between 4 and 15;prompt/first_framesare paths to the production package;- Failed tasks are not billed; retries are listed separately;
- Old per-shot tasks can use
id, buth3_tasks.jsonalways usesgeneration_id.
Delivery Package
final.mp4
subtitles.srt
vo.wav
vo.csv
music/A-E.wav + cue_sheet.csv
credits.md
source_list.csv
fact_check.csv
final_qc.md
Hard Rules
- Images are default generated by the user via GPT; AI does not call image APIs; image tools are only allowed when
image_mode=agentand the user explicitly approves; - Video defaults to a single version; only add a second version if the first is unusable;
- Generated video is only for ambient sound/dialogue, not for music/BGM;
- 768P source material may be 1344×768 (7:4), final delivery at 1920×1080;
- First frames must be 16:9, otherwise image-to-video aspect ratio will drift;
- Historical photos must cite sources; AI visuals must be labeled "reenactment";
- Subtitles: 16–20 characters per line, max 2 lines, ≥100px left/right margins;
- Each music segment should have 1.5–2 seconds of handle; low point is not silence;
- Costs are calculated based on task logs, not from memory;
- Before delivery, use ffprobe to verify resolution/frame rate/audio;
- First finalize narration, then shots; default is one narration line spanning 2–3 shots; one shot per line is a special case;
- Narration should not fill the entire shot; a 5-second narration paired with a 5-second shot will feel rushed; leave 0.3–1.0 seconds of breathing room between sentences;
- Narration can be poetic, but poetry must have physical/action anchors; only the explanatory section requires one hard fact per sentence; do not mix the two standards;
- After narration is locked, do not rewrite the entire project because of one changed line; first run
vo_diff.py, then only modify affected files; - After G4 prompts are completed, first remind the user to generate images; only after the user starts generating should you work on parallel tasks that do not depend on images/video;
- One narration segment can span multiple shots; a normal shot should have at most one narration segment; a
long_take=yeslong shot can contain multiple narration segments, but all must be within the shot; - The breathing room window must contain the shot cut point; do not require sentence start/end to align with the cut point; when there is a range, use the larger breathing room;
- After the v0 animatic is produced, first remind the user to check the breathing room between sentences; do not produce first frames or generate video before confirmation;
- The voice must be auditioned with 2–3 candidates and selected by the user; do not default to a specific TTS;
- Narration defaults to "clear but not plain": first explain the character/event/cause-effect, then use concrete imagery and short sentences to create space; allow adding 1–2 sentences, but each must bring new information or a new image; do not pad with adjectives;
- Each beat in
beats.csvmust be claimed by exactly one shot; each shot and each narration segment must have beats covering them; missing, duplicate, or out-of-order beats are caught byvalidate.py; segments.csv: one segment ≤15 seconds; cut order within the segment is sequential, each cut has a keyframe, each shot appears only once; the start/end of each cut must equal the cumulative time inshots.csv; useexport_h3.pyto produce the H3 multi-image alignment production package;- Opening card: G0 sets duration, G2.5 sets text, G3 writes
0-1 static=yes, G4 generates image, G5 does not use H3.
Provider
config/providers.yaml is documentation; the machine configuration is providers.json (generated by init_project.py, validated by timeline.py).
Defaults: images=user_gpt, video=minimax_h3, narration=capcut_tts, music=local_midi_fluidsynth, editing=capcut, QC=ffmpeg.
The image provider is always human; this does not change with configuration.
Commands
python scripts/init_project.py --root my-film --profile short --duration 30 --shots 10 --segments 2
python scripts/timeline.py --shots shots.csv --vo vo.csv --vo-out vo_report.csv --project project.json --min-gap 0.4
python scripts/timeline.py --shots shots.csv --vo vo.csv --max-density 0.85 --allow-single
python scripts/narration_lint.py --text vo.csv --style lyrical --max-chars 28
python scripts/validate.py --shots shots.csv --vo vo.csv --beats beats.csv --segments segments.csv --project project.json
python scripts/validate.py --shots shots.csv --vo vo.csv --beats beats.csv --segments segments.csv --project project.json --strict-files
python scripts/validate_tasks.py --tasks h3_tasks.json --segments segments.csv
python scripts/selftest.py
python scripts/export_h3.py --shots shots.csv --segments segments.csv --prompts h3_prompts.csv --out h3_package
python scripts/timeline.py --shots shots.csv --vo vo.csv --animatic animatic.mp4
python scripts/vo_gap_report.py --vo vo.csv --audio vo_scratch.wav --out vo_gap.md
python scripts/vo_diff.py --old vo_versions/vo_v1.csv --new vo.csv --out vo_diff.md
python scripts/vo2srt.py --vo vo.csv --out subtitles.srt --max-chars 18
python scripts/contact_sheet.py --clips clips --out review --frames 6
python scripts/cost_report.py --tasks tasks.json --out cost.csv --default-model MiniMax-H3
Scripts: init_project.py, validate.py, selftest.py, export_h3.py, timeline.py, narration_lint.py, vo2srt.py, vo_gap_report.py, vo_diff.py, contact_sheet.py, cost_report.py. --animatic defaults to black frames if first frames are missing; --animatic-missing error can change this to error out.
validate.py handles structural contracts (schema / beats / segment cuts / coverage); G3 does not check keyframe files by default, G5 checks with --strict-files. timeline.py --vo handles timing (breathing room / density / long takes). Run both; they are not interchangeable.
Error Handling
- Video failure: Check task status; failed tasks are not billed; switch to H3-Max or modify the first frame, do not blindly re-run;
- Face changes/multiple hands: Regenerate or switch to profile/back view;
- Action did not occur: Regenerate, do not fix in editing;
- Subtitle overflow: Change style/break lines, do not shrink to unreadable;
- Music jarring: Add pickup, expression ramp, handle; do not hard cut;
- Export proportion wrong: Go back to project and set 1920×1080, do not stretch.
References
SOP.md: Human-readable workflow and checklistreferences/: Stage details (including00_setup.md,09_vo_spans.md,10_model_routing.md,11_narration.md,12_change_control.md,13_parallel_work.md,14_v0_animatic.md,15_beats_segments.md)providers/: Replaceable toolstemplates/: Project card, shot table, prompts, review forms, cue sheet, credits, final QC